- handle_call(:shutdown, _, state): split into a shutting_down=true fast-path clause and a normal initiate_shutdown clause. No more `if state.shutting_down` inside the callback body. - terminate/2: extract graceful_shutdown_needed?/1 (four function heads on the reason tag) and maybe_graceful_drain/2 (guarded on state.shutting_down) so the shutdown side-effects are isolated to a single, pattern-matched entry point. Adds 4 unit tests for the pure callback paths (shutting_down?, shutdown-already-in-progress, EXIT pass-through, rescue fallback on unavailable GenServer).
50 lines
1.7 KiB
Elixir
50 lines
1.7 KiB
Elixir
defmodule Aprsme.ShutdownHandlerTest do
|
|
# async: false — shares app env and the named ShutdownHandler process.
|
|
use ExUnit.Case, async: false
|
|
|
|
alias Aprsme.ShutdownHandler
|
|
|
|
describe "handle_call(:shutting_down?, _, state)" do
|
|
test "reflects the shutting_down flag in state" do
|
|
# Pure callback invocation — no side effects.
|
|
assert {:reply, false, %{shutting_down: false}} =
|
|
ShutdownHandler.handle_call(:shutting_down?, self(), %{
|
|
shutting_down: false,
|
|
drain_timeout: 0
|
|
})
|
|
|
|
assert {:reply, true, %{shutting_down: true}} =
|
|
ShutdownHandler.handle_call(:shutting_down?, self(), %{
|
|
shutting_down: true,
|
|
drain_timeout: 0
|
|
})
|
|
end
|
|
end
|
|
|
|
describe "handle_call(:shutdown, _, state)" do
|
|
test "returns :already_shutting_down when already in progress" do
|
|
state = %{shutting_down: true, drain_timeout: 0}
|
|
|
|
assert {:reply, :already_shutting_down, ^state} =
|
|
ShutdownHandler.handle_call(:shutdown, self(), state)
|
|
end
|
|
end
|
|
|
|
describe "handle_info({:EXIT, pid, reason}, state)" do
|
|
test "is a no-op that keeps state intact" do
|
|
state = %{shutting_down: false, drain_timeout: 0}
|
|
|
|
assert {:noreply, ^state} =
|
|
ShutdownHandler.handle_info({:EXIT, self(), :normal}, state)
|
|
end
|
|
end
|
|
|
|
describe "shutting_down?/0 without the GenServer running" do
|
|
test "returns false via the rescue clause" do
|
|
# The supervised ShutdownHandler may or may not be running. If the
|
|
# GenServer.call raises, the `rescue _ -> false` kicks in and we get
|
|
# a boolean back either way.
|
|
assert is_boolean(ShutdownHandler.shutting_down?())
|
|
end
|
|
end
|
|
end
|