Packages
testcontainers
2.0.0
2.3.1
2.3.0
2.2.0
2.1.0
2.1.0-rc1
2.0.0
2.0.0-rc3
2.0.0-rc2
2.0.0-rc
1.14.1
1.14.0
1.13.5
1.13.4
1.13.3
1.13.2
1.13.1
1.13.0
1.12.0
1.11.8
1.11.7
1.11.6
1.11.5
1.11.4
1.11.3
1.11.2
1.11.1
1.11.0
1.10.5
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.4
1.8.3
1.8.2
1.8.1
1.8.0
1.7.0
1.6.0
1.5.1
1.5.0
1.4.2
1.4.1
1.4.0
1.3.1
1.3.0
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.3
1.1.2
1.1.1
1.1.0
1.0.1
1.0.0
1.0.0-beta.1
1.0.0-beta
0.9.3
0.9.2
0.9.1
0.9.0
Testcontainers is an Elixir library that supports ExUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
Current section
Files
Jump to
Current section
Files
lib/wait_strategy/http_wait_strategy.ex
defmodule Testcontainers.HttpWaitStrategy do
@moduledoc """
Considers the container as ready when a http request is successful.
"""
@timeout 60_000
@max_retries 10
@typedoc """
The HttpWaitStrategy struct
## Options
- `:endpoint` - The endpoint to request
- `:port` - The exposed port of your container
Verification Options:
- `:status_code` - Check if the request responds with the given status code
- `:match` - Run your custom matcher on the given response. A 1-arity function
taking a response as first parameter and must return a boolean
Request Options:
- `:protocol` - which protocol to use, defaults to `http`
- `:method` - the request method, one of [`:head`, `:get`, `:delete`, `:trace`, `:options`, `:post`, `:put`, `:patch`]
- `:timeout` - The timeout of the request (in milliseconds), defaults to `5000`
- `:headers` - Apply any headers to your request
"""
@type t() :: %__MODULE__{
endpoint: String.t(),
port: integer(),
protocol: String.t(),
method: :get | :post | :patch | :put | :delete | :head | :options | :trace,
timeout: integer(),
headers: [{binary(), binary()}],
status_code: integer(),
match: (map() -> boolean())
}
defstruct [
:endpoint,
:port,
# request options
protocol: "http",
method: :get,
headers: [],
timeout: @timeout,
max_retries: @max_retries,
# verification options
status_code: nil,
match: nil
]
# Public interface
@doc """
Creates a new HttpWaitStrategy to wait until a http requests succeeds.
"""
def new(endpoint, port, options \\ []) do
struct(%__MODULE__{endpoint: endpoint, port: port}, options)
end
# Private functions and implementations
defimpl Testcontainers.WaitStrategy do
alias Testcontainers.HttpWaitStrategy
alias Testcontainers.Container
@impl true
def wait_until_container_is_ready(wait_strategy, container, _conn) do
client = build_request(wait_strategy, container)
raw_response =
Tesla.request(client,
url: wait_strategy.endpoint,
method: wait_strategy.method,
headers: wait_strategy.headers
)
with {:ok, response} <- validate_response(raw_response),
:ok <- verify_status_code(wait_strategy, response),
:ok <- verify_match(wait_strategy, response) do
:ok
else
{:error, reason} ->
{:error, reason, wait_strategy}
end
end
# Response evaluation
defp validate_response({:ok, response}), do: {:ok, response}
defp validate_response({:error, reason}), do: {:error, reason}
defp verify_status_code(wait_strategy, %{status: status_code})
when not is_nil(wait_strategy.status_code) and
status_code == wait_strategy.status_code,
do: :ok
defp verify_status_code(wait_strategy, response) when not is_nil(wait_strategy.status_code),
do:
{:error,
"Status Code does not match. Expected: #{wait_strategy.status_code} Received: #{response.status}"}
defp verify_status_code(wait_strategy, _) when is_nil(wait_strategy.status_code), do: :ok
defp verify_match(wait_strategy, response)
when not is_nil(wait_strategy.match) and is_function(wait_strategy.match) do
case wait_strategy.match.(response) do
true -> :ok
false -> {:error, "Matcher function failed"}
end
end
defp verify_match(_, _), do: :ok
# Request composition
defp build_request(wait_strategy, container) do
base_url = get_base_url(wait_strategy, container)
request_timeout = round(wait_strategy.timeout / wait_strategy.max_retries)
Tesla.client([
{Tesla.Middleware.BaseUrl, base_url: base_url},
{Tesla.Middleware.Timeout, timeout: request_timeout},
{Tesla.Middleware.Retry,
delay: 500,
max_retries: wait_strategy.max_retries,
max_delay: 5_000,
should_retry: fn
{:ok, _response}, _env, _context -> false
{:error, _reason}, _env, _context -> true
end}
])
end
defp get_base_url(%HttpWaitStrategy{} = wait_strategy, %Container{} = container) do
port = Container.mapped_port(container, wait_strategy.port)
"#{wait_strategy.protocol}://#{Testcontainers.get_host()}:#{port}/"
end
end
end