http_gun/testing

Starts offline clients that answer from a script of exchanges, to test code that takes an http_gun.Client.

let assert Ok(req) = request.to("https://api.example.com/orders/7")
let script =
  testing.script([
    testing.exchange(
      request.set_body(req, <<>>),
      testing.Respond(
        response.new(200) |> response.set_body([<<"{\"id\":7}">>]),
        testing.Finished([]),
      ),
    ),
  ])
let assert Ok(client) = testing.playback(script, config.default())
let assert Ok(buffered) = http_gun.send(client, request.set_body(req, <<>>))

A playback client never opens a connection and ignores the destination policy. Each request must match the next exchange: a mismatch fails with PlaybackMismatch(position) and leaves the exchange in place, and a request after the last fails with PlaybackExhausted. Concurrent requests are matched in admission order.

Matching is exact by default: method, URL, headers and body bytes, after the configuration’s redaction (config.with_redaction) is applied to both sides. ignoring_headers skips headers such as a timestamp or a signature, and matching replaces the comparison.

exchange drops the credential headers of redaction.default() from the request it stores, so a script never holds a caller’s credentials.

Types

How a scripted response body ends.

pub type Ending {
  Finished(trailers: List(#(String, String)))
  Aborted(error.Failure)
  Abandoned
}

Constructors

  • Finished(trailers: List(#(String, String)))

    The body completed, with these trailers.

  • Aborted(error.Failure)

    The body failed after its chunks.

  • Abandoned

    The client closed the body before it completed, as a recorded early stop replays.

A request and the reply that answers it.

pub type Exchange =
  @internal Exchange

How a scripted exchange answers.

pub type Reply {
  Respond(
    response: response.Response(List(BitArray)),
    ending: Ending,
  )
  Reject(error.Failure)
}

Constructors

  • Respond(
      response: response.Response(List(BitArray)),
      ending: Ending,
    )

    Respond with a status, headers and body chunks, then end.

  • Reject(error.Failure)

    Fail before any response, for example with a connection failure.

Ordered exchanges and the way requests are matched against them.

pub type Script =
  @internal Script

Values

pub fn exchange(
  request: request.Request(BitArray),
  reply: Reply,
) -> Exchange

Pair an expected request with its reply.

pub fn exchanges(script: Script) -> List(Exchange)

The exchanges of a script, in order.

pub fn ignoring_headers(
  script: Script,
  names: List(String),
) -> Script

Leave these headers, compared without case, out of matching on both sides, for values that change on every run such as a date or a signature.

pub fn match_key(
  redaction: redaction.Redaction,
  request: request.Request(BitArray),
) -> request.Request(BitArray)

The form of a request that playback compares: redaction applied, the host lowercased, an empty path as /, header names lowercased and headers sorted by name.

pub fn matching(
  script: Script,
  compare: fn(
    request.Request(BitArray),
    request.Request(BitArray),
  ) -> Bool,
) -> Script

Replace the exact comparison. compare receives the expected and the actual request as match_key forms them: redacted, normalised, without ignored headers.

pub fn playback(
  script: Script,
  settings: config.Config,
) -> Result(http_gun.Client, http_gun.StartError)

Start an offline client that answers from script. The script is checked first: statuses must be 200..599, bodies whole bytes, and the whole script within 16 MiB.

Each call starts a client with its own cursor at the first exchange. The immutable Script can be reused to start independent clients. Views made from one client share its cursor; changing correlation does not create another replay or affect matching. Stop each started client separately.

pub fn reply(exchange: Exchange) -> Reply

The reply of an exchange.

pub fn request(exchange: Exchange) -> request.Request(BitArray)

The expected request of an exchange, as stored.

pub fn script(exchanges: List(Exchange)) -> Script

A script of exchanges, matched in order and exactly.

✨ Search Document