Testing a server polling an Agent

Hello all, I have a problem with a Producer I’m building, which is polling an Agent for data to process.

This is the Producer:

defmodule Twinkle.Producer.Server do
  use GenStage

  alias Twinkle.Producer.Impl

  def init(state) do
    {:producer, state}
  end

  def handle_cast(:check_messages, state) do
    messages = Impl.take
    GenStage.cast(__MODULE__, :check_messages)
    {:noreply, Enum.into(messages, []), state - Enum.count(messages)}
  end

  def handle_demand(_demand, state) do
    GenStage.cast(__MODULE__, :check_messages)
    {:noreply, [], state}
  end
end

The Agent is quite straightforward with nothing particularly weird, it just stores a MapSet.

I’m having a lot of problems testing this thing, because I can’t send something inside the agent and retrieve it, the polling process “consumes” the agent and even if the vals are in I always have an empty list in return.

This is my non working test:

test "check_messages to return the Agent's content" do
  Impl.put("1", "Test")
  assert {:noreply, [%{body: "Test", sid: "2"}], 1} = Server.handle_cast(:check_messages, 1)
end

I guess the only way is to stop all processes and check the handle_cast when it’s basically just waiting, but definitely not sure it’s the right thing to do.

Suggestions?

You can have the test instantiate its own agent and producer. Pass the agent name/pid as an argument to the producer’s init, store it in the state, and pass it to the Impl functions (assuming that’s the agent wrapper). This way you can test many instances in parallel and they don’t interfere with each other.

I’m not super familiar with GenStage but I suspect you can also use self() instead of hardcoding the name as __MODULE__ in the handlers.

1 Like