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/port_wait_strategy.ex
# SPDX-License-Identifier: MIT
defmodule Testcontainers.WaitStrategy.PortWaitStrategy do
@moduledoc """
Considers container as ready as soon as a command runs successfully inside the container.
"""
defstruct [:ip, :port, :timeout]
@doc """
Creates a new CommandWaitStrategy to wait until the given command executes successfully inside the container.
"""
def new(ip, port, timeout \\ 5000),
do: %__MODULE__{ip: ip, port: port, timeout: timeout}
end
defimpl Testcontainers.WaitStrategy, for: Testcontainers.WaitStrategy.PortWaitStrategy do
alias Testcontainers.Docker
alias Testcontainers.Container
@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_port(wait_strategy.ip, host_port, wait_strategy.timeout) do
{:ok, :port_is_open} ->
:ok
_ ->
:timer.sleep(100)
wait_until_container_is_ready(wait_strategy, id_or_name)
end
end
end
def wait_for_port(ip, port, timeout \\ 1000)
when is_binary(ip) and is_integer(port) and is_integer(timeout) do
wait_for_port(ip, port, timeout, :os.system_time(:millisecond))
end
defp wait_for_port(ip, port, timeout, start_time)
when is_binary(ip) and is_integer(port) and is_integer(timeout) and is_integer(start_time) do
if timeout + start_time < :os.system_time(:millisecond) do
{:error, :timeout}
else
if port_open?(ip, port) do
{:ok, :port_is_open}
else
# Sleep for 500 ms, then retry
:timer.sleep(500)
wait_for_port(ip, port, timeout, start_time)
end
end
end
defp port_open?(ip, port, timeout \\ 1000)
when is_binary(ip) and is_integer(port) and is_integer(timeout) do
case :gen_tcp.connect(~c"#{ip}", port, [:binary, active: false], timeout) do
{:ok, socket} ->
:gen_tcp.close(socket)
true
{:error, _reason} ->
false
end
end
end