ExUnit.start(seed: 42) defmodule CounterLabTest do use ExUnit.Case, async: false defp with_counter(fun) do {:ok, counter} = Agent.start_link(fn -> 0 end) try do fun.(counter) after Agent.stop(counter) end end test "separate get and update lose an update despite one owner" do with_counter(fn counter -> parent = self() tasks = for _ <- 1..2 do Task.async(fn -> old = Agent.get(counter, & &1) send(parent, {:ready, self()}) receive do :go -> Agent.update(counter, fn _current -> old + 1 end) after 5_000 -> raise "barrier timeout" end end) end clients = for _ <- 1..2 do receive do {:ready, pid} -> pid after 5_000 -> raise "client timeout" end end Enum.each(clients, &send(&1, :go)) Enum.each(tasks, &Task.await(&1, 5_000)) assert Agent.get(counter, & &1) == 1 end) end test "one update callback owns the entire increment" do with_counter(fn counter -> 1..20 |> Enum.map(fn _ -> Task.async(fn -> Agent.update(counter, &(&1 + 1)) end) end) |> Enum.each(&Task.await(&1, 5_000)) assert Agent.get(counter, & &1) == 20 end) end end