Public API for starting and controlling dummy HTTP servers for integration tests.
The main entry points are:
start_link/1– start a new HTTP dummy serverchild_spec/1– embed the server directly in your supervision treestub/2andstub/3– define stub rules for HTTP requestsexpect/3– define expectation rules for HTTP requests- route management helpers –
add_route/2,add_routes/2,set_routes/2,update_route/2,delete_route/2 calls/1– fetch the history of received requestsreset!/1– reset server state between testshost/1,port/1,endpoint/1,url/2– discover where the server is listeningstop/1– stop the server
Documentation: README on GitHub and HexDocs.
Summary
Types
A recorded HTTP call, suitable for assertions in tests.
Endpoint information for pointing external systems (for example ejabberd) at a running HttpDouble instance.
Matcher used to select which HTTP requests should be affected by a stub/expectation.
Response specification used by stubs, expectations and static routes.
A server reference; can be a PID or a registered name.
Functions
Adds a single static route at runtime.
Adds multiple static routes at runtime.
Returns the list of all HTTP calls observed by a server.
Returns a child_spec/1 suitable for embedding the server under a supervisor.
Deletes a route, identified either by :id or by {method, path}.
Returns a convenient endpoint map %{host, port, base_url} for pointing
external systems (for example ejabberd) at this HttpDouble instance.
Adds an expectation rule.
Returns the logical host the server advertises (for configuration injection).
Returns the TCP port the server is currently listening on.
Resets the server state
Replaces the full static route table at runtime.
Starts a new dummy HTTP server.
Stops the server gracefully.
Adds a stub rule using an options keyword list.
Convenience stub form: stub(server, matcher, response_spec).
Updates a single route, identified either by :id or by {method, path}.
Builds a full URL for a given path (string or list of segments) using the server's current endpoint.
Types
@type call_record() :: %{ conn_id: non_neg_integer(), request: HttpDouble.Request.t(), timestamp: integer(), rule_id: reference() | nil, route_id: reference() | nil, action: term() }
A recorded HTTP call, suitable for assertions in tests.
@type endpoint() :: %{host: String.t(), port: non_neg_integer(), base_url: String.t()}
Endpoint information for pointing external systems (for example ejabberd) at a running HttpDouble instance.
@type matcher() :: :any | {:method, atom() | String.t()} | {:path, String.t()} | {:prefix, String.t()} | {:path_regex, Regex.t()} | {:route, atom() | String.t(), String.t()} | {:fn, (HttpDouble.Request.t(), HttpDouble.MockRule.meta() -> boolean())} | map()
Matcher used to select which HTTP requests should be affected by a stub/expectation.
Supported shapes:
:any– match any request{:method, method}– e.g.{:method, :get}or{:method, "POST"}{:path, path}– exact path match, e.g.{:path, "/health"}{:prefix, prefix}– prefix path match, e.g.{:prefix, "/api"}{:path_regex, re}– regular expression on the request path{:route, method, path}– method + path match{:fn, fun}– predicatefun.(request, meta) :: boolean- a map with keys like
:method,:path,:host,:query,:headers,:bodythat will be interpreted byHttpDouble.MockRule
@type response_spec() :: map() | HttpDouble.Response.t() | {:delay, non_neg_integer(), response_spec()} | :timeout | :no_reply | :close | {:close, response_spec()} | {:raw, iodata()} | {:partial, [iodata()]} | {:fun, (HttpDouble.Request.t(), HttpDouble.MockRule.meta() -> response_spec())} | [response_spec()]
Response specification used by stubs, expectations and static routes.
Supported forms:
- simple maps:
%{status: 200, body: "ok"}%{status: 201, json: %{result: "accepted"}}%{status: 204}(empty body)
- explicit response struct
HttpDouble.Response.t() {:delay, ms, inner}– delay sendinginnerbymsmilliseconds:timeoutor:no_reply– do not send any reply:close– immediately close the TCP connection{:close, inner}– sendinnerthen close the connection{:raw, iodata}– send raw bytes as-is (can be invalid HTTP){:partial, [iodata()]}– send raw chunks one by one{:fun, fun}– callbackfun.(request, meta) :: response_spec- a non-empty list of response specs – used sequentially per matcher
@type server() :: GenServer.server()
A server reference; can be a PID or a registered name.
Functions
Adds a single static route at runtime.
Adds multiple static routes at runtime.
@spec calls(server()) :: [call_record()]
Returns the list of all HTTP calls observed by a server.
@spec child_spec(Keyword.t()) :: Supervisor.child_spec()
Returns a child_spec/1 suitable for embedding the server under a supervisor.
Deletes a route, identified either by :id or by {method, path}.
Returns a convenient endpoint map %{host, port, base_url} for pointing
external systems (for example ejabberd) at this HttpDouble instance.
@spec expect(server(), matcher(), response_spec()) :: {:ok, reference()}
Adds an expectation rule.
Semantics are the same as for stub/3, but expectations are intended to be
asserted via calls/1 in your tests. The engine will keep track of how many
times each expectation was used.
Returns the logical host the server advertises (for configuration injection).
@spec port(server()) :: non_neg_integer()
Returns the TCP port the server is currently listening on.
@spec reset!(server()) :: :ok
Resets the server state:
- clears all routes
- clears all mock rules and expectations
- clears call history
Replaces the full static route table at runtime.
@spec start_link(Keyword.t()) :: GenServer.on_start()
Starts a new dummy HTTP server.
Options:
:port– TCP port to listen on (defaults to0, meaning a random free port):host– logical host name to report inendpoint/1(default:"127.0.0.1"):ip– IP tuple to bind to (default:{127, 0, 0, 1}):routes– list of static route definitions (see README for examples):mode– one of::mock_first(default) – try mock rules first, fall back to static routes:routes_only– ignore mock rules, use only static routes:mock_only– only apply mock rules, unknown requests are 404
:name– optional registered name (viaRegistry.HttpDouble.ServerRegistry)
@spec stop(server()) :: :ok
Stops the server gracefully.
Adds a stub rule using an options keyword list.
This is the most flexible form and supports all fields of HttpDouble.MockRule.
@spec stub(server(), matcher(), response_spec()) :: {:ok, reference()}
Convenience stub form: stub(server, matcher, response_spec).
Examples:
# Always return 200/"ok" for GET /health
{:ok, _rule} =
HttpDouble.stub(server, %{method: "GET", path: "/health"}, %{status: 200, body: "ok"})
# Sequential responses for POST /api/messages
{:ok, _rule} =
HttpDouble.stub(server, %{method: :post, path: "/api/messages"}, [
%{status: 201, json: %{result: "accepted"}},
%{status: 503, body: "unavailable"}
])
Updates a single route, identified either by :id or by {method, path}.
Builds a full URL for a given path (string or list of segments) using the server's current endpoint.