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.
116 lines
3.3 KiB
Elixir
116 lines
3.3 KiB
Elixir
defmodule Ash.Test.Reactor.NotificationsTest do
|
|
@moduledoc false
|
|
use ExUnit.Case, async: true
|
|
use Mimic
|
|
import ExUnit.CaptureLog
|
|
alias Ash.Reactor.Notifications
|
|
|
|
describe "init/1" do
|
|
test "it starts an agent" do
|
|
{:ok, context} = Notifications.init(%{})
|
|
|
|
assert [] == agent_get(context.ash_notification_agent)
|
|
end
|
|
|
|
test "when there are already notifications in the context it stores them in the agent" do
|
|
notifications = build_notifications()
|
|
|
|
{:ok, context} =
|
|
Notifications.init(%{ash_notifications: notifications})
|
|
|
|
enqueued = agent_get(context.ash_notification_agent)
|
|
assert enqueued == notifications
|
|
end
|
|
|
|
test "when there are already notifications in the context it removes them" do
|
|
notifications = build_notifications()
|
|
|
|
{:ok, context} =
|
|
Notifications.init(%{ash_notifications: notifications})
|
|
|
|
refute is_map_key(context, :ash_notifications)
|
|
end
|
|
end
|
|
|
|
describe "halt/1" do
|
|
setup do
|
|
{:ok, context} = Notifications.init(%{})
|
|
{:ok, context: context}
|
|
end
|
|
|
|
test "it stops the agent", %{context: context} do
|
|
[agent | _] = context.ash_notification_agent
|
|
|
|
{:ok, context} = Notifications.halt(context)
|
|
assert context.ash_notification_agent == []
|
|
refute Process.alive?(agent)
|
|
end
|
|
|
|
test "it moves any queued notifications into the context", %{context: context} do
|
|
notifications = build_notifications()
|
|
:ok = Notifications.enqueue_notifications(context, notifications)
|
|
{:ok, context} = Notifications.halt(context)
|
|
|
|
assert context.ash_notifications == notifications
|
|
end
|
|
end
|
|
|
|
describe "complete/2" do
|
|
setup do
|
|
{:ok, context} = Notifications.init(%{})
|
|
{:ok, context: context}
|
|
end
|
|
|
|
test "it publishes any queued notifications", %{context: context} do
|
|
notifications = build_notifications()
|
|
:ok = Notifications.enqueue_notifications(context, notifications)
|
|
|
|
expect(Notifications, :publish, fn _context, actual ->
|
|
assert actual == notifications
|
|
[]
|
|
end)
|
|
|
|
assert {:ok, :result} = Notifications.complete(:result, context)
|
|
end
|
|
|
|
test "it logs a warning when there are unpublished notifications", %{context: context} do
|
|
notifications = build_notifications()
|
|
:ok = Notifications.enqueue_notifications(context, notifications)
|
|
|
|
expect(Notifications, :publish, fn _context, notifications -> notifications end)
|
|
|
|
assert capture_log(fn ->
|
|
assert {:ok, :result} = Notifications.complete(:result, context)
|
|
end) =~ "Missed 3 notifications"
|
|
end
|
|
|
|
test "it stops the agent", %{context: context} do
|
|
[agent | _] = context.ash_notification_agent
|
|
|
|
{:ok, :result} = Notifications.complete(:result, context)
|
|
refute Process.alive?(agent)
|
|
end
|
|
end
|
|
|
|
describe "error/2" do
|
|
setup do
|
|
{:ok, context} = Notifications.init(%{})
|
|
{:ok, context: context}
|
|
end
|
|
|
|
test "it stops the agent", %{context: context} do
|
|
[agent | _] = context.ash_notification_agent
|
|
|
|
:ok = Notifications.error([:errors], context)
|
|
refute Process.alive?(agent)
|
|
end
|
|
end
|
|
|
|
defp build_notifications(how_many \\ 3) do
|
|
for i <- 1..how_many do
|
|
Ash.Notifier.Notification.new(__MODULE__.FakeResource, data: %{count: i})
|
|
end
|
|
end
|
|
|
|
defp agent_get([agent | _]), do: Agent.get(agent, & &1)
|
|
end
|