Current section

Files

Jump to
ecto integration_test sql test_transaction.exs
Raw

integration_test/sql/test_transaction.exs

defmodule Ecto.Integration.TestTransactionTest do
use ExUnit.Case
alias Ecto.Integration.TestRepo
alias Ecto.Pool
@ref {Ecto.Pool, Ecto.Adapters.SQL.Sandbox, elem(TestRepo.__pool__, 1)}
@timeout :infinity
test "sandbox pool is lazy" do
assert {:ok, _} = Ecto.Adapters.SQL.Sandbox.start_link(UnknownModuleBecauseLazy, [])
end
test "begin, restart and rollback" do
assert_transaction(:raw)
assert :ok = Ecto.Adapters.SQL.begin_test_transaction(TestRepo)
assert_transaction(:sandbox)
assert :ok = Ecto.Adapters.SQL.restart_test_transaction(TestRepo)
assert_transaction(:sandbox)
assert :ok = Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
assert_transaction(:raw)
after
Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
end
test "restart_test_transaction begins a transaction if one is not running" do
assert_transaction(:raw)
assert :ok = Ecto.Adapters.SQL.restart_test_transaction(TestRepo)
assert_transaction(:sandbox)
assert :ok = Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
assert_transaction(:raw)
after
Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
end
test "begin_test_transaction inside another transaction should timeout" do
TestRepo.transaction(fn ->
assert {:timeout, _} =
catch_exit(Ecto.Adapters.SQL.restart_test_transaction(TestRepo,
[timeout: 200, pool_timeout: 200]))
end)
after
Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
end
test "restart_test_transaction inside another transaction should timeout" do
TestRepo.transaction(fn ->
assert {:timeout, _} =
catch_exit(Ecto.Adapters.SQL.restart_test_transaction(TestRepo,
[timeout: 200, pool_timeout: 200]))
end)
after
Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
end
test "begin_test_transaction should fail when it has already began" do
Ecto.Adapters.SQL.begin_test_transaction(TestRepo)
assert_raise RuntimeError, ~r"cannot begin test transaction", fn ->
Ecto.Adapters.SQL.begin_test_transaction(TestRepo)
end
after
Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
end
test "sandbox mode does not disconnect on transaction break" do
Ecto.Adapters.SQL.begin_test_transaction(TestRepo)
{:ok, conn} = TestRepo.transaction(fn() ->
assert %{conn: conn} = Process.get(@ref)
Pool.break(@ref, @timeout)
conn
end)
TestRepo.transaction(fn() ->
assert %{conn: ^conn} = Process.get(@ref)
{_, pid} = conn
assert Process.alive?(pid)
end)
after
Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
end
test "sandbox mode does not disconnect on run break" do
Ecto.Adapters.SQL.begin_test_transaction(TestRepo)
{_, pool_mod, pool} = @ref
try do
Pool.run(pool_mod, pool, @timeout, fn(conn, _) ->
throw(conn)
end)
catch
:throw, conn ->
TestRepo.transaction(fn() ->
assert %{conn: ^conn} = Process.get(@ref)
end)
end
after
Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
end
test "sandbox mode does not disconnect if transaction caller dies" do
Ecto.Adapters.SQL.begin_test_transaction(TestRepo)
_ = Process.flag(:trap_exit, true)
parent = self()
{:ok, task} = Task.start_link(fn ->
TestRepo.transaction(fn() ->
assert %{conn: conn} = Process.get(@ref)
send(parent, {:go, self(), conn})
:timer.sleep(@timeout)
end)
end)
assert_receive {:go, ^task, conn}, @timeout
Process.exit(task, :shutdown)
assert_receive {:EXIT, ^task, :shutdown}, @timeout
TestRepo.transaction(fn() ->
%{conn: ^conn} = Process.get(@ref)
{_, pid} = conn
assert Process.alive?(pid)
end)
after
Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
end
test "sandbox mode does not disconnect if run caller dies" do
Ecto.Adapters.SQL.begin_test_transaction(TestRepo)
_ = Process.flag(:trap_exit, true)
parent = self()
{:ok, task} = Task.start_link(fn ->
{_, pool_mod, pool} = @ref
Pool.run(pool_mod, pool, @timeout, fn(conn, _) ->
send(parent, {:go, self(), conn})
:timer.sleep(@timeout)
end)
end)
assert_receive {:go, ^task, conn}, @timeout
Process.exit(task, :shutdown)
assert_receive {:EXIT, ^task, :shutdown}, @timeout
TestRepo.transaction(fn() ->
assert %{conn: ^conn} = Process.get(@ref)
{_, pid} = conn
assert Process.alive?(pid)
end)
after
Ecto.Adapters.SQL.rollback_test_transaction(TestRepo)
end
test "raw mode disconnects on transaction break" do
conn = TestRepo.transaction(fn() ->
assert %{conn: conn} = Process.get(@ref)
Pool.break(@ref, @timeout)
conn
end)
TestRepo.transaction(fn() ->
%{conn: other} = Process.get(@ref)
assert conn != other
end)
end
test "raw mode disconnects if transaction caller dies" do
_ = Process.flag(:trap_exit, true)
parent = self()
{:ok, task} = Task.start_link(fn ->
TestRepo.transaction(fn() ->
assert %{conn: conn1} = Process.get(@ref)
send(parent, {:go, self(), conn1})
:timer.sleep(@timeout)
end)
end)
assert_receive {:go, ^task, conn1}, @timeout
Process.exit(task, :shutdown)
assert_receive {:EXIT, ^task, :shutdown}, @timeout
TestRepo.transaction(fn() ->
%{conn: conn2} = Process.get(@ref)
assert conn1 !== conn2
{_, pid1} = conn1
refute Process.alive?(pid1)
{_, pid2} = conn2
assert Process.alive?(pid2)
end)
end
test "raw mode does not disconnects if run caller dies" do
_ = Process.flag(:trap_exit, true)
parent = self()
{:ok, task} = Task.start_link(fn ->
{_, pool_mod, pool} = @ref
Pool.run(pool_mod, pool, @timeout, fn(conn, _) ->
send(parent, {:go, self(), conn})
:timer.sleep(@timeout)
end)
end)
assert_receive {:go, ^task, conn}, @timeout
Process.exit(task, :shutdown)
assert_receive {:EXIT, ^task, :shutdown}, @timeout
TestRepo.transaction(fn() ->
assert %{conn: ^conn} = Process.get(@ref)
{_, pid} = conn
assert Process.alive?(pid)
end)
end
defp assert_transaction(mode) do
TestRepo.transaction(fn ->
{_, pool, _, _} = TestRepo.__pool__
assert Ecto.Adapters.SQL.Sandbox.mode(pool) === mode
end)
end
end