Current section

Files

Jump to
testcontainers lib wait_strategy command_wait_strategy.ex
Raw

lib/wait_strategy/command_wait_strategy.ex

# SPDX-License-Identifier: MIT
# Original by: Marco Dallagiacoma @ 2023 in https://github.com/dallagi/excontainers
# Modified by: Jarl André Hübenthal @ 2023
defmodule Testcontainers.WaitStrategy.CommandWaitStrategy do
@moduledoc """
Considers container as ready as soon as a command runs successfully inside the container.
"""
defstruct [:command]
@doc """
Creates a new CommandWaitStrategy to wait until the given command executes successfully inside the container.
"""
def new(command), do: %__MODULE__{command: command}
end
defimpl Testcontainers.WaitStrategy,
for: Testcontainers.WaitStrategy.CommandWaitStrategy do
alias Testcontainers.Docker.Exec
def wait_until_container_is_ready(wait_strategy, id_or_name) do
case exec_and_wait(id_or_name, wait_strategy.command) do
{:ok, {0, _stdout}} ->
:ok
_ ->
:timer.sleep(100)
wait_until_container_is_ready(wait_strategy, id_or_name)
end
end
def exec_and_wait(container_id, command, options \\ []) do
timeout_ms = options[:timeout_ms]
{:ok, exec_id} = exec(container_id, command)
case wait_for_exec_result(exec_id, timeout_ms) do
{:ok, exec_info} -> {:ok, {exec_info.exit_code, ""}}
{:error, :timeout} -> {:error, :timeout}
end
end
def exec(container_id, command) do
{:ok, exec_id} = Exec.create(container_id, command)
:ok = Exec.start(exec_id)
{:ok, exec_id}
end
defp wait_for_exec_result(exec_id, timeout_ms, started_at \\ monotonic_time()) do
case Exec.inspect(exec_id) do
{:ok, %{running: true}} -> do_wait_unless_timed_out(exec_id, timeout_ms, started_at)
{:ok, finished_exec_status} -> {:ok, finished_exec_status}
end
end
defp do_wait_unless_timed_out(exec_id, timeout_ms, started_at) do
if out_of_time(started_at, timeout_ms) do
{:error, :timeout}
else
:timer.sleep(100)
wait_for_exec_result(exec_id, timeout_ms, started_at)
end
end
defp monotonic_time, do: System.monotonic_time(:millisecond)
defp out_of_time(started_at, timeout_ms), do: monotonic_time() - started_at > timeout_ms
end