Stampede.Channels (stampede v0.2.0)

Copy Markdown View Source

A Phoenix Channels client for load tests.

{:ok, socket} = Stampede.Channels.connect("ws://localhost:4000/socket", params: %{token: token})
{:ok, _reply} = Stampede.Channels.join(socket, "room:lobby")
{:ok, _reply} = Stampede.Channels.push(socket, "room:lobby", "new_msg", %{body: "hi"})
{:ok, payload} = Stampede.Channels.await(socket, "room:lobby", "new_msg")

Each socket is a process linked to the caller. It sends heartbeats, matches every reply to the request it answers, and keeps the last 1,000 messages pushed or broadcast by the server until they are read with await/4.

Metrics

Inside a run, sockets record:

  • "ws.connect" and "ws.connect.errors"
  • "ws.disconnects" - connections closed by the server or the network
  • "channel.join" and "channel.join.errors"
  • "channel.push" and "channel.push.errors"
  • "channel.leave" and "channel.leave.errors"
  • "channel.messages" - messages pushed or broadcast by the server
  • "channel.messages.dropped" - messages dropped because the socket already held 1,000 unread ones

Error replies, timeouts and closed connections all count as errors.

Summary

Functions

Waits until the server pushes or broadcasts event on topic, and returns its payload.

Pushes event with payload to topic without waiting for a reply.

Closes the connection and waits for the socket to stop.

Connects to the Phoenix socket at url.

Joins topic, sending payload to the channel's join/3 callback.

Pushes event with payload to topic and waits for the reply.

Types

socket()

@type socket() :: pid()

Functions

await(socket, topic, event, timeout_or_opts \\ [])

@spec await(socket(), String.t(), String.t(), timeout() | keyword()) ::
  {:ok, term()} | {:error, term()}

Waits until the server pushes or broadcasts event on topic, and returns its payload.

Messages that arrived before the call are looked at first, oldest first. Returns {:error, :timeout} if no such message arrives in time.

The last argument is a timeout in milliseconds, or a list of options:

  • :timeout - how long to wait, in milliseconds. Defaults to 5_000.

  • :match - a function that gets each payload and returns whether it is the one to wait for. Useful when other VUs broadcast the same event:

    Stampede.Channels.await(socket, "room:lobby", "shout", match: &(&1["from"] == vu.id))

cast(socket, topic, event, payload \\ %{})

@spec cast(socket(), String.t(), String.t(), map()) :: :ok

Pushes event with payload to topic without waiting for a reply.

close(socket)

@spec close(socket()) :: :ok

Closes the connection and waits for the socket to stop.

connect(url, opts \\ [])

@spec connect(String.t(), keyword()) :: {:ok, socket()} | {:error, term()}

Connects to the Phoenix socket at url.

url is the socket's endpoint as given to the JavaScript client, such as "ws://localhost:4000/socket". /websocket is added to its path unless it is already there.

Options

  • :params - query parameters sent with the connection, often used for authentication
  • :headers - extra headers for the upgrade request
  • :vsn - the serializer version, "2.0.0" (the default) or "1.0.0". A vsn query parameter in url takes precedence.
  • :connect_timeout - how long to wait for the connection, in milliseconds. Defaults to 10_000.
  • :heartbeat_interval - how often to send a heartbeat, in milliseconds, or nil to never send one. Defaults to 30_000, like the JavaScript client. The connection is closed when a heartbeat is still unanswered by the time the next one is due.
  • :transport_opts - options for :gen_tcp or :ssl, given to Mint.HTTP.connect/4

Returns {:error, reason} when the connection fails, such as a Mint.TransportError when nothing is listening, or a Mint.WebSocket.UpgradeFailureError when the socket's connect/3 refuses it.

join(socket, topic, payload \\ %{}, opts \\ [])

@spec join(socket(), String.t(), map(), keyword()) :: {:ok, term()} | {:error, term()}

Joins topic, sending payload to the channel's join/3 callback.

Returns {:ok, response} when the channel accepts the join and {:error, response} when it refuses it. It may also return {:error, :timeout}, or {:error, {:closed, reason}} when the connection closes first.

Options

  • :timeout - how long to wait for the reply, in milliseconds. Defaults to 5_000.
  • :metric - the timing to record the join as, or nil to record nothing. Defaults to "channel.join".

leave(socket, topic, opts \\ [])

@spec leave(socket(), String.t(), keyword()) :: :ok | {:error, term()}

Leaves topic.

Takes the same options as join/4, with :metric defaulting to "channel.leave".

push(socket, topic, event, payload \\ %{}, opts \\ [])

@spec push(socket(), String.t(), String.t(), map(), keyword()) ::
  {:ok, term()} | {:error, term()}

Pushes event with payload to topic and waits for the reply.

Returns {:ok, response} or {:error, response}, depending on what the channel's handle_in/3 replied. Use cast/4 for events the channel does not reply to.

Takes the same options as join/4, with :metric defaulting to "channel.push".