有一个简单的GenServer
,可以在异步调用中执行简单的Ecto查询:
defmodule App.Notifications.Manager do
def send(user, event) do
IO.write "manager pid "
IO.inspect self()
GenServer.cast(__MODULE__, {:email, user, event})
end
def handle_cast({:email, user, event}, state) do
IO.write "manager server pid "
IO.inspect self()
App.Repo.all(App.User)
{:noreply, state}
end
end
以及看起来像这样的相关测试:
defmodule App.Notifications.EventManagerTest do
use App.ModelCase
test "send a message", context do
IO.puts "start test"
IO.inspect self()
App.Notifications.Manager.send(context.user, context.event)
IO.puts "finish test"
end
end
测试本身以共享模式执行
defmodule App.ModelCase do
#...
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(App.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(App.Repo, {:shared, self()})
end
:ok
end
end
现在,mix test
正在导致竞争条件:
..................start test
#PID<0.499.0>
manager pid #PID<0.499.0>
finish test
.manager server pid #PID<0.283.0>
12:31:04.787 [error] GenServer App.Notifications.Manager terminating
** (stop) exited in: GenServer.call(#PID<0.500.0>, {:checkout, #Reference<0.0.1.1627>, true, 15000}, 5000)
** (EXIT) shutdown: "owner #PID<0.499.0> exited with: shutdown"
(db_connection) lib/db_connection/ownership/proxy.ex:32: DBConnection.Ownership.Proxy.checkout/2
(db_connection) lib/db_connection.ex:701: DBConnection.checkout/2
(db_connection) lib/db_connection.ex:608: DBConnection.run/3
(db_connection) lib/db_connection.ex:449: DBConnection.prepare_execute/4
(ecto) lib/ecto/adapters/sql.ex:224: Ecto.Adapters.SQL.sql_call/6
(ecto) lib/ecto/adapters/sql.ex:396: Ecto.Adapters.SQL.execute_and_cache/7
(ecto) lib/ecto/repo/queryable.ex:127: Ecto.Repo.Queryable.execute/5
(ecto) lib/ecto/repo/queryable.ex:40: Ecto.Repo.Queryable.all/4
(ave88) lib/ave88/notifications/manager.ex:46: Ave88.Notifications.Manager.handle_cast/2
(stdlib) gen_server.erl:615: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:681: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
..............................................
Finished in 2.9 seconds (1.1s on load, 1.7s on tests)
65 tests, 0 failures
如您所见,handle_cast
在测试结束后发生。应用使用最新版本的db_connection
- 1.0.0-rc.1
和ecto
- 2.0.0-rc.6
。
答案 0 :(得分:2)
执行此操作的一种方法是添加仅返回虚拟值的handle_call
,然后在测试中cast
之后调用它,以确保执行所有排队的强制转换由GenServer
。这是有效的,因为GenServer
按照他们收到的顺序处理所有演员/电话。如果您长时间运行10 {1}}然后1 cast
,call
1}}将在10 call
s逐个完成执行后返回。
在cast
中,添加:
App.Notifications.Manager
然后,在你的测试中,
之后def handle_call(:ping, _from, state) do
{:reply, :pong, state}
end
添加
App.Notifications.Manager.send(context.user, context.event)