# `Lockstep.Test`
[🔗](https://github.com/b-erdem/lockstep/blob/v0.1.0/lib/lockstep/test.ex#L1)

ExUnit case template for controlled concurrency tests.

    defmodule MyConcurrencyTest do
      use Lockstep.Test, iterations: 200, strategy: :fair_pct

      ctest "two workers race on shared state" do
        state = Lockstep.spawn(fn -> stateful_loop(0) end)
        parent = self()

        for _ <- 1..2 do
          Lockstep.spawn(fn ->
            Lockstep.send(state, {:get, self()})
            val = Lockstep.recv()
            Lockstep.send(state, {:put, val + 1})
            Lockstep.send(parent, :done)
          end)
        end

        Lockstep.recv()
        Lockstep.recv()
        Lockstep.send(state, {:get, self()})
        assert Lockstep.recv() == 2
      end
    end

## Options

  * `:iterations` (default `100`) — how many randomized schedules to try
  * `:strategy`   (default `:pct`) — `:random | :pct | :fair_pct`
  * `:seed`       (optional)       — top-level RNG seed; per-iteration
                                      seeds are derived deterministically
  * `:max_steps`  (default `1000`) — hard limit on scheduling steps
                                      per iteration

# `ctest`
*macro* 

Define a controlled-concurrency test. The body is run repeatedly with
different schedules until either all iterations pass or one finds a bug.

At compile time, the body is scanned for bare `send`/`receive`/`spawn`
and OTP-`GenServer`/`Task`/`Process` calls that should be routed
through Lockstep instead. Each occurrence prints a compile-time
warning. Suppress a specific warning by qualifying the call (e.g.
`Kernel.send(p, m)` to mean "I really do want raw send here").

# `vanilla_run`
*macro* 

Run a controlled test body N times, with the body's AST automatically
rewritten to use `Lockstep.*` calls everywhere `GenServer.call`,
`Task.async`, `send`, `spawn`, etc. appear. Useful inside an
ordinary `test` block when you want to keep the body looking like
vanilla OTP.

    test "lost update finds the race" do
      assert_raise Lockstep.BugFound, fn ->
        Lockstep.Test.vanilla_run iterations: 100, strategy: :pct, seed: 1 do
          {:ok, c} = GenServer.start_link(MyMod.Counter, 0)
          tasks = for _ <- 1..2 do
            Task.async(fn ->
              v = GenServer.call(c, :get)
              GenServer.call(c, {:set, v + 1})
            end)
          end
          Task.await_many(tasks)
          assert GenServer.call(c, :get) == 2
        end
      end
    end

---

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