Я пытаюсь написать тесты для случая, когда мне нужно протестировать метод с from(...) |> lock("FOR UPDATE")
и убедиться, что строка будет заблокирована от других процессов. Я пытался написать этот тест:
defmodule Chain.BalanceTest do
use Chain.DataCase
describe "concurrent" do
setup do
{:ok, %Chain.Address{id: id}} = Chain.Address.create_address(%{user_id: 1, nonce: 0})
:ok
end
test "test locking" do
parent = self()
%Chain.Address{id: id} = from(a in Chain.Address) |> Repo.one()
{:ok, new_pid} =
Task.start_link(fn ->
assert_receive :wait, 5000
Repo.transaction(fn ->
address = Chain.Address.lock_address(id)
Apex.ap("1 - #{address.nonce}")
Chain.Address.update_nonce(address)
end)
send(parent, :done)
end)
Repo.transaction(fn ->
address = Chain.Address.lock_address(id)
Apex.ap("2 - #{address.nonce}")
send(new_pid, :wait)
Chain.Address.update_nonce(address)
end)
assert_receive :done, 5000
fetched = Chain.Address.get!(id)
assert fetched.nonce == 2
end
end
end
Проблема в том, что он работает на уровне изоляции транзакций и всегда работает, даже если я удаляю lock
из Chain.Addres.lock_address
. Я попытался Sandbox.checkout
в Task
, но в этом случае Task
процесс не видит этот адрес, потому что родительский процесс не зафиксировал его.
Так есть ли способ вызвать состояние гонки во время теста и \ или сохранить данные идиоматическим способом c, чтобы другой процесс мог прочитать их и не испортил все другие тесты?