Skip to content

Instantly share code, notes, and snippets.

@rranelli
Created August 26, 2020 00:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rranelli/36f5b1e384fd3bb0df29afaef6e59870 to your computer and use it in GitHub Desktop.
Save rranelli/36f5b1e384fd3bb0df29afaef6e59870 to your computer and use it in GitHub Desktop.
defmodule ControlPlane.CircuitBreakerTest do
use ExUnit.Case
import ExUnit.Callbacks
alias ControlPlane.CircuitBreaker
defmodule Worker do
use GenServer
def start_link(args \\ %{}),
do: GenServer.start_link(__MODULE__, args)
@impl true
def init(init_args) do
init_args[:test_pid] && send(init_args[:test_pid], {:worker_pid, self()})
init_args[:boom!] && raise "boom!"
(msg = init_args[:receive]) && assert_receive ^msg
{:ok, init_args}
end
@impl true
def handle_info(:boom!, _state), do: raise("boom!")
end
test "worker is stopped on `break!/1` and can be restarted" do
start_supervised!({CircuitBreaker, Worker})
assert CircuitBreaker.available?(Worker)
assert :ok = CircuitBreaker.break!(Worker)
assert CircuitBreaker.unavailable?(Worker)
assert :ok = CircuitBreaker.restart(Worker)
assert CircuitBreaker.available?(Worker)
end
test "circuit breaker startup fails if the worker startup fails" do
assert {:error, reason} = start_supervised({CircuitBreaker, {Worker, boom!: true}})
assert {{:shutdown, {:failed_to_start_child, :worker, _exception}}, _child} = reason
end
test "circuit breaker automatically restarts a failed child" do
_pid = start_supervised!({CircuitBreaker, {Worker, [[test_pid: self()]]}})
# First, we'll get notified from the worker with its identity
assert_receive {:worker_pid, worker_pid}
ref = Process.monitor(worker_pid)
# Now, we abnormally terminate the worker ...
send(worker_pid, :boom!)
# ... which should notify us of its death via `monitor` ...
assert_receive {:DOWN, ^ref, :process, ^worker_pid, _reason}
# ... Meaning the subsystem is now unavailable
:timer.sleep(100)
assert CircuitBreaker.unavailable?(Worker)
# After a little while, the worker will be restarted ...
assert_receive {:worker_pid, new_worker_pid}
when new_worker_pid != worker_pid,
2_000
# Meaning the subsystem is now *available*
:timer.sleep(100)
assert CircuitBreaker.available?(Worker)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment