Packages

Testcontainers for Gleam: typed container lifecycle with crash-safe cleanup and a native Unix-socket Docker client.

Current section

Files

Jump to
testcontainer src testcontainer@wait.erl
Raw

src/testcontainer@wait.erl

-module(testcontainer@wait).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/testcontainer/wait.gleam").
-export([none/0, log/1, log_times/2, port/1, http/2, http_with_status/3, health_check/0, command/1, all_of/1, any_of/1, with_timeout/2, with_poll_interval/2, base/1, timeout_ms/1, poll_interval_ms/1, describe/1]).
-export_type([wait_strategy/0, wait_strategy_base/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque wait_strategy() :: {wait_strategy,
wait_strategy_base(),
integer(),
integer()}.
-type wait_strategy_base() :: for_none |
{for_log, binary(), integer()} |
{for_port, integer()} |
{for_http, integer(), binary(), integer()} |
for_health_check |
{for_command, list(binary()), integer()} |
{all_of, list(wait_strategy())} |
{any_of, list(wait_strategy())}.
-file("src/testcontainer/wait.gleam", 32).
-spec wrap(wait_strategy_base()) -> wait_strategy().
wrap(Base) ->
{wait_strategy, Base, 60000, 1000}.
-file("src/testcontainer/wait.gleam", 39).
?DOC(
" \"No wait\" - succeeds immediately. This is the default when a\n"
" `ContainerSpec` is built with `container.new/1` and no `wait_for/2`\n"
" is set.\n"
).
-spec none() -> wait_strategy().
none() ->
wrap(for_none).
-file("src/testcontainer/wait.gleam", 45).
?DOC(
" Waits until the container's combined stdout/stderr stream contains the\n"
" given message at least once.\n"
).
-spec log(binary()) -> wait_strategy().
log(Message) ->
wrap({for_log, Message, 1}).
-file("src/testcontainer/wait.gleam", 50).
?DOC(" Like `log/1` but waits until the message appears at least `times` times.\n").
-spec log_times(binary(), integer()) -> wait_strategy().
log_times(Message, Times) ->
wrap({for_log, Message, Times}).
-file("src/testcontainer/wait.gleam", 55).
?DOC(" Waits until the given (TCP) container port accepts connections from the host.\n").
-spec port(integer()) -> wait_strategy().
port(Port) ->
wrap({for_port, Port}).
-file("src/testcontainer/wait.gleam", 61).
?DOC(
" Waits until an HTTP GET to the given path on the given container port\n"
" returns status 200.\n"
).
-spec http(integer(), binary()) -> wait_strategy().
http(Port, Path) ->
wrap({for_http, Port, Path, 200}).
-file("src/testcontainer/wait.gleam", 66).
?DOC(" Like `http/2` but waits for a custom expected status code.\n").
-spec http_with_status(integer(), binary(), integer()) -> wait_strategy().
http_with_status(Port, Path, Status) ->
wrap({for_http, Port, Path, Status}).
-file("src/testcontainer/wait.gleam", 72).
?DOC(
" Waits for Docker to report the container's HEALTHCHECK as `healthy`.\n"
" The image must define a HEALTHCHECK for this to terminate.\n"
).
-spec health_check() -> wait_strategy().
health_check() ->
wrap(for_health_check).
-file("src/testcontainer/wait.gleam", 77).
?DOC(" Runs a command inside the container and waits until it exits 0.\n").
-spec command(list(binary())) -> wait_strategy().
command(Cmd) ->
wrap({for_command, Cmd, 0}).
-file("src/testcontainer/wait.gleam", 82).
?DOC(" Composes strategies - succeeds when ALL inner strategies succeed.\n").
-spec all_of(list(wait_strategy())) -> wait_strategy().
all_of(Strategies) ->
wrap({all_of, Strategies}).
-file("src/testcontainer/wait.gleam", 87).
?DOC(" Composes strategies - succeeds as soon as ANY inner strategy succeeds.\n").
-spec any_of(list(wait_strategy())) -> wait_strategy().
any_of(Strategies) ->
wrap({any_of, Strategies}).
-file("src/testcontainer/wait.gleam", 93).
?DOC(
" Sets the per-strategy timeout (default 60 s). Negative values are\n"
" clamped to 0 (the strategy times out immediately).\n"
).
-spec with_timeout(wait_strategy(), integer()) -> wait_strategy().
with_timeout(Strategy, Ms) ->
Safe = case Ms < 0 of
true ->
0;
false ->
Ms
end,
case Strategy of
{wait_strategy, Base, _, Poll} ->
{wait_strategy, Base, Safe, Poll}
end.
-file("src/testcontainer/wait.gleam", 105).
?DOC(
" Sets the polling interval (default 1 s). Values <= 0 are clamped to 1\n"
" to avoid a hot-spin loop.\n"
).
-spec with_poll_interval(wait_strategy(), integer()) -> wait_strategy().
with_poll_interval(Strategy, Ms) ->
Safe = case Ms < 1 of
true ->
1;
false ->
Ms
end,
case Strategy of
{wait_strategy, Base, Timeout, _} ->
{wait_strategy, Base, Timeout, Safe}
end.
-file("src/testcontainer/wait.gleam", 118).
?DOC(false).
-spec base(wait_strategy()) -> wait_strategy_base().
base(Strategy) ->
case Strategy of
{wait_strategy, B, _, _} ->
B
end.
-file("src/testcontainer/wait.gleam", 125).
?DOC(" Returns the configured timeout in milliseconds.\n").
-spec timeout_ms(wait_strategy()) -> integer().
timeout_ms(Strategy) ->
case Strategy of
{wait_strategy, _, T, _} ->
T
end.
-file("src/testcontainer/wait.gleam", 132).
?DOC(" Returns the configured poll interval in milliseconds.\n").
-spec poll_interval_ms(wait_strategy()) -> integer().
poll_interval_ms(Strategy) ->
case Strategy of
{wait_strategy, _, _, P} ->
P
end.
-file("src/testcontainer/wait.gleam", 139).
?DOC(" Human-readable description used in `WaitTimedOut` / `WaitFailed` errors.\n").
-spec describe(wait_strategy()) -> binary().
describe(Strategy) ->
case Strategy of
{wait_strategy, Base, Timeout, Poll} ->
Base_desc = case Base of
for_none ->
<<"none"/utf8>>;
{for_log, Message, Times} ->
<<<<<<<<"log("/utf8, Message/binary>>/binary, ", "/utf8>>/binary,
(erlang:integer_to_binary(Times))/binary>>/binary,
")"/utf8>>;
{for_port, Port} ->
<<<<"port("/utf8, (erlang:integer_to_binary(Port))/binary>>/binary,
")"/utf8>>;
{for_http, Port@1, Path, Status} ->
<<<<<<<<<<<<"http("/utf8,
(erlang:integer_to_binary(Port@1))/binary>>/binary,
", "/utf8>>/binary,
Path/binary>>/binary,
", "/utf8>>/binary,
(erlang:integer_to_binary(Status))/binary>>/binary,
")"/utf8>>;
for_health_check ->
<<"health_check"/utf8>>;
{for_command, Cmd, Expected} ->
<<<<<<<<"command("/utf8,
(gleam@string:join(Cmd, <<" "/utf8>>))/binary>>/binary,
", "/utf8>>/binary,
(erlang:integer_to_binary(Expected))/binary>>/binary,
")"/utf8>>;
{all_of, Strats} ->
<<<<"all_of("/utf8,
(gleam@string:join(
gleam@list:map(Strats, fun describe/1),
<<", "/utf8>>
))/binary>>/binary,
")"/utf8>>;
{any_of, Strats@1} ->
<<<<"any_of("/utf8,
(gleam@string:join(
gleam@list:map(Strats@1, fun describe/1),
<<", "/utf8>>
))/binary>>/binary,
")"/utf8>>
end,
<<<<<<<<<<Base_desc/binary, " [timeout="/utf8>>/binary,
(erlang:integer_to_binary(Timeout))/binary>>/binary,
", poll="/utf8>>/binary,
(erlang:integer_to_binary(Poll))/binary>>/binary,
"]"/utf8>>
end.