Packages
testcontainers
0.9.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
# SPDX-License-Identifier: MIT
defmodule Testcontainers.WaitStrategy.HttpWaitStrategy do
@moduledoc """
Considers container as ready as soon as a command runs successfully inside the container.
"""
defstruct [:ip, :port, :path, :timeout]
@doc """
Creates a new CommandWaitStrategy to wait until the given command executes successfully inside the container.
"""
def new(ip, port, path \\ "/", timeout \\ 5000),
do: %__MODULE__{ip: ip, port: port, path: path, timeout: timeout}
end
defimpl Testcontainers.WaitStrategy, for: Testcontainers.WaitStrategy.HttpWaitStrategy do
alias Testcontainers.Container
alias Testcontainers.Docker
@impl true
def wait_until_container_is_ready(wait_strategy, id_or_name) do
with {:ok, %Container{} = container} <- Docker.Api.get_container(id_or_name) do
host_port = Container.mapped_port(container, wait_strategy.port)
case wait_for_http(wait_strategy.ip, host_port, wait_strategy.path, wait_strategy.timeout) do
{:ok, :http_is_ready} ->
:ok
_ ->
:timer.sleep(100)
wait_until_container_is_ready(wait_strategy, id_or_name)
end
end
end
defp wait_for_http(ip, port, path, timeout)
when is_binary(ip) and is_integer(port) and is_binary(path) and is_integer(timeout) do
wait_for_http(ip, port, path, timeout, :os.system_time(:millisecond))
end
defp wait_for_http(ip, port, path, timeout, start_time)
when is_binary(ip) and is_integer(port) and is_binary(path) and is_integer(timeout) and
is_integer(start_time) do
if timeout + start_time < :os.system_time(:millisecond) do
{:error, :timeout}
else
case http_request(ip, port, path) do
{:ok, _response} ->
{:ok, :http_is_ready}
{:error, _reason} ->
# Sleep for 500 ms, then retry
:timer.sleep(500)
wait_for_http(ip, port, path, timeout, start_time)
end
end
end
defp http_request(ip, port, path) do
url = "http://" <> ip <> ":" <> Integer.to_string(port) <> path
case :httpc.request(:get, {to_charlist(url), []}, [], []) do
{:ok, {{~c"HTTP/1.1", 200, _reason_phrase}, _headers, _body}} ->
{:ok, :http_ok}
{:ok, {{~c"HTTP/1.1", status_code, _reason_phrase}, _headers, _body}}
when status_code != 200 ->
{:error, {:unexpected_status_code, status_code}}
{:error, reason} ->
{:error, reason}
end
end
end