ProtonStream.Fake (proton_stream v1.8.4)

View Source

A test double that "looks like a port" to ProtonStream.

Instead of spawning the muontrap executable, ProtonStream can be configured with fake: test_pid. When faked, every port operation is forwarded to test_pid as a message, and the ProtonStream GenServer itself stands in for the port handle. This lets a test drive and observe the process I/O entirely with assert_receive/refute_receive.

Message vocabulary

Messages sent to the test pid by the fake:

  • {:protonstream_open, command, ps} - the fake "port" was opened for command. ps is the ProtonStream GenServer pid and is the handle you use to inject artificial output.
  • {:protonstream_command, ps, frame} - ProtonStream wrote frame (a framed stdin/ack binary) to the port.
  • {:protonstream_closed, ps} - the port was closed.

To inject port output, the test calls send_data/2, which sends the ProtonStream GenServer a {test_pid, {:data, frames}} message - the same shape a real port uses. frames must speak the framed wire protocol (see stdout_frame/1, stderr_frame/1, and exit_frame/1).

Example

{:ok, ps} = ProtonStream.open("cat", [], fake: self())
^ps = ProtonStream.Fake.assert_opened("cat")

# observe what ProtonStream writes to stdin
send(ps, {self(), {:command, "hello"}})
assert_receive {:protonstream_command, ^ps, <<1, 0, 5, "hello">>}

# inject artificial stdout back to the owner
ProtonStream.Fake.send_data(ps, ProtonStream.Fake.stdout_frame("hi\n"))
assert_receive {^ps, {:data, "hi\n"}}

ProtonStream.Fake.send_data(ps, ProtonStream.Fake.exit_frame(0))

Summary

Functions

Assert that the fake port for ps was closed.

Assert that a fake port was opened for command and return the ProtonStream GenServer pid (the handle used to inject output).

Build an exit frame carrying status (a signed 32-bit exit status).

Inject data (framed port output) into the ProtonStream GenServer ps as if it came from the port.

Build a stderr frame carrying data, as the port would emit it.

Build a stdout frame carrying data, as the port would emit it.

Functions

assert_closed(ps, timeout \\ 1000)

@spec assert_closed(ps :: pid(), timeout()) :: :ok

Assert that the fake port for ps was closed.

Must be called from the configured test pid.

assert_opened(command, timeout \\ 1000)

@spec assert_opened(command :: binary(), timeout()) :: pid()

Assert that a fake port was opened for command and return the ProtonStream GenServer pid (the handle used to inject output).

Must be called from the configured test pid.

exit_frame(status)

@spec exit_frame(integer()) :: binary()

Build an exit frame carrying status (a signed 32-bit exit status).

send_data(ps, data)

@spec send_data(ps :: pid(), data :: binary()) :: :ok

Inject data (framed port output) into the ProtonStream GenServer ps as if it came from the port.

Use the stdout_frame/1, stderr_frame/1, and exit_frame/1 helpers to build data.

stderr_frame(data)

@spec stderr_frame(iodata()) :: binary()

Build a stderr frame carrying data, as the port would emit it.

stdout_frame(data)

@spec stdout_frame(iodata()) :: binary()

Build a stdout frame carrying data, as the port would emit it.