# `Supertester.SupervisorHelpers`
[🔗](https://github.com/nshkrdotcom/supertester/blob/v0.6.0/lib/supertester/supervisor_helpers.ex#L1)

Specialized testing utilities for supervision trees.

This module provides helpers for testing supervisor behavior, restart strategies,
and supervision tree structures.

## Key Features

- Test restart strategies (one_for_one, one_for_all, rest_for_one)
- Trace supervision events
- Verify supervision tree structure
- Wait for supervisor stabilization

## Usage

    import Supertester.SupervisorHelpers

    test "supervisor restart strategy" do
      {:ok, supervisor} = setup_isolated_supervisor(MySupervisor)

      result = test_restart_strategy(supervisor, :one_for_one, {:kill_child, :worker_1})

      assert result.restarted == [:worker_1]
      assert result.not_restarted == [:worker_2, :worker_3]
    end

# `child_structure`

```elixir
@type child_structure() ::
  {child_id :: term(), module :: module()}
  | {child_id :: term(), tree_structure()}
```

# `restart_scenario`

```elixir
@type restart_scenario() ::
  {:kill_child, child_id :: term()}
  | {:kill_children, [child_id :: term()]}
  | {:cascade_failure, start_child_id :: term()}
```

# `supervision_event`

```elixir
@type supervision_event() ::
  {:child_started, child_id :: term(), pid()}
  | {:child_terminated, child_id :: term(), pid(), reason :: term()}
  | {:child_restarted, child_id :: term(), old_pid :: pid(), new_pid :: pid()}
```

# `test_result`

```elixir
@type test_result() :: %{
  restarted: [term()],
  not_restarted: [term()],
  supervisor_alive: boolean()
}
```

# `tree_structure`

```elixir
@type tree_structure() :: %{
  supervisor: module(),
  strategy: atom(),
  children: [child_structure()]
}
```

# `assert_supervision_tree_structure`

```elixir
@spec assert_supervision_tree_structure(Supervisor.supervisor(), tree_structure()) ::
  :ok
```

Asserts supervision tree matches expected structure.

## Parameters

- `supervisor` - The supervisor PID
- `expected` - Expected tree structure

## Examples

    test "supervision tree structure" do
      {:ok, root} = setup_isolated_supervisor(RootSupervisor)

      assert_supervision_tree_structure(root, %{
        supervisor: RootSupervisor,
        strategy: :one_for_one,
        children: [
          {:cache, CacheServer},
          {:workers, %{
            supervisor: WorkerSupervisor,
            strategy: :one_for_all,
            children: [
              {:worker_1, Worker},
              {:worker_2, Worker}
            ]
          }}
        ]
      })
    end

# `get_active_child_count`

```elixir
@spec get_active_child_count(Supervisor.supervisor()) :: non_neg_integer()
```

Gets the count of active children in a supervisor.

## Parameters

- `supervisor` - The supervisor PID

## Returns

Number of active children

## Examples

    count = get_active_child_count(supervisor)
    assert count == 3

# `test_restart_strategy`

```elixir
@spec test_restart_strategy(Supervisor.supervisor(), atom(), restart_scenario()) ::
  test_result()
```

Tests supervisor restart strategies with various failure scenarios.

## Parameters

- `supervisor` - The supervisor PID or name
- `strategy` - Expected strategy (:one_for_one, :one_for_all, :rest_for_one)
- `scenario` - The failure scenario to test

## Examples

    test "one_for_one restarts only failed child" do
      {:ok, supervisor} = setup_isolated_supervisor(MySupervisor)

      result = test_restart_strategy(supervisor, :one_for_one, {:kill_child, :worker_1})

      assert result.restarted == [:worker_1]
      assert result.not_restarted == [:worker_2, :worker_3]
    end

# `trace_supervision_events`

```elixir
@spec trace_supervision_events(
  Supervisor.supervisor(),
  keyword()
) :: {:ok, (-&gt; [supervision_event()])}
```

Traces all supervision events for verification.

## Parameters

- `supervisor` - The supervisor PID to trace
- `opts` - Options (currently unused)

## Returns

`{:ok, stop_fn}` where stop_fn returns the list of traced events

## Examples

    test "supervisor restart behavior" do
      {:ok, supervisor} = setup_isolated_supervisor(MySupervisor)
      {:ok, stop_trace} = trace_supervision_events(supervisor)

      # Cause some failures
      children = Supervisor.which_children(supervisor)
      Enum.each(children, fn {_id, pid, _type, _mods} ->
        Process.exit(pid, :kill)
      end)

      # Get events
      events = stop_trace.()

      # Verify restart sequence
      assert length(events) >= 6  # 3 terminates + 3 restarts
    end

# `wait_for_supervisor_stabilization`

```elixir
@spec wait_for_supervisor_stabilization(Supervisor.supervisor(), timeout()) ::
  :ok | {:error, :timeout}
```

Waits until supervisor has all children running and stable.

## Parameters

- `supervisor` - The supervisor PID
- `timeout` - Timeout in milliseconds (default: 5000)

## Examples

    test "supervisor recovery" do
      {:ok, supervisor} = setup_isolated_supervisor(MySupervisor)

      # Cause chaos
      children = Supervisor.which_children(supervisor)
      Enum.each(children, fn {_id, pid, _type, _mods} ->
        Process.exit(pid, :kill)
      end)

      # Wait for stabilization
      assert :ok = wait_for_supervisor_stabilization(supervisor)

      # All should be alive
      assert_all_children_alive(supervisor)
    end

---

*Consult [api-reference.md](api-reference.md) for complete listing*
