mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 13:33:20 +12:00
James Harton
139058d4c0
Thanks to @carlgleisner for the [detailed reproduction](https://github.com/carlgleisner/reactor_notification_worker_issue). The problem was caused by an attempt to not have nested reactors indepdently publish their notifications separate to the parents but contained a logic flaw which caused the agent to not start, but only the first time you try and use a given reactor. The fix involves _always_ starting a notification agent for each reactor, but nesting them. When a reactor completes it either publishes it's notifications to the parent reactor or to ash if there are no parent reactors.
127 lines
2.9 KiB
Elixir
127 lines
2.9 KiB
Elixir
defmodule Ash.Test.Reactor.TransactionTest do
|
|
@moduledoc false
|
|
use ExUnit.Case, async: false
|
|
use Mimic
|
|
|
|
alias Ash.Test.Domain
|
|
|
|
defmodule Post do
|
|
@moduledoc false
|
|
use Ash.Resource, data_layer: Ash.DataLayer.Mnesia, domain: Domain
|
|
|
|
attributes do
|
|
uuid_primary_key :id
|
|
attribute :title, :string, allow_nil?: false, public?: true
|
|
end
|
|
|
|
actions do
|
|
default_accept :*
|
|
defaults [:destroy, create: :*]
|
|
end
|
|
end
|
|
|
|
setup do
|
|
ExUnit.CaptureLog.capture_log(fn ->
|
|
Ash.DataLayer.Mnesia.start(Domain, [Post])
|
|
end)
|
|
|
|
on_exit(fn ->
|
|
ExUnit.CaptureLog.capture_log(fn ->
|
|
:mnesia.stop()
|
|
:mnesia.delete_schema([node()])
|
|
end)
|
|
end)
|
|
end
|
|
|
|
test "when the transaction completes successfully it returns the last result" do
|
|
defmodule SuccessfulNoReturnTransactionReactor do
|
|
@moduledoc false
|
|
use Ash.Reactor
|
|
|
|
ash do
|
|
default_domain(Domain)
|
|
end
|
|
|
|
transaction :create_posts, Post do
|
|
create :post_1, Post, :create do
|
|
inputs(%{title: value("About Marty McFly")})
|
|
end
|
|
|
|
create :post_2, Post, :create do
|
|
inputs(%{title: value("About Doc Brown")})
|
|
end
|
|
end
|
|
end
|
|
|
|
assert {:ok, %{title: "About Doc Brown"}} = Reactor.run(SuccessfulNoReturnTransactionReactor)
|
|
end
|
|
|
|
test "when the transaction completes successfully it returns the specified result" do
|
|
defmodule SuccessfulNamedReturnTransactionReactor do
|
|
@moduledoc false
|
|
use Ash.Reactor
|
|
|
|
ash do
|
|
default_domain(Domain)
|
|
end
|
|
|
|
transaction :create_posts, Post do
|
|
create :post_1, Post, :create do
|
|
inputs(%{title: value("About Marty McFly")})
|
|
end
|
|
|
|
create :post_2, Post, :create do
|
|
inputs(%{title: value("About Doc Brown")})
|
|
end
|
|
|
|
return :post_1
|
|
end
|
|
end
|
|
|
|
assert {:ok, %{title: "About Marty McFly"}} =
|
|
Reactor.run!(SuccessfulNamedReturnTransactionReactor)
|
|
end
|
|
|
|
test "when the transaction fails it is rolled back" do
|
|
defmodule FailAndRollBackTransactionReactor do
|
|
@moduledoc false
|
|
use Ash.Reactor
|
|
|
|
ash do
|
|
default_domain(Domain)
|
|
end
|
|
|
|
transaction :create_posts, Post do
|
|
create :post_1, Post, :create do
|
|
inputs(%{title: value("About Marty McFly")})
|
|
end
|
|
|
|
step :fail do
|
|
run fn _, _ ->
|
|
raise "hell"
|
|
end
|
|
end
|
|
|
|
return :post_1
|
|
end
|
|
end
|
|
|
|
Ash.DataLayer
|
|
|> expect(:rollback, fn resources, reason ->
|
|
assert resources == [Post]
|
|
assert Exception.message(reason) == "hell"
|
|
|
|
raise reason
|
|
end)
|
|
|
|
FailAndRollBackTransactionReactor
|
|
|> Reactor.run(%{}, %{}, async?: false)
|
|
|> Ash.Test.assert_has_error(fn
|
|
%Reactor.Error.Invalid.RunStepError{error: error} ->
|
|
Exception.message(error) =~ "hell"
|
|
|
|
_ ->
|
|
false
|
|
end)
|
|
end
|
|
end
|