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/reaper.ex
defmodule Testcontainers.Reaper do
use Supervisor
def start_link(opts \\ []) do
Supervisor.start_link(__MODULE__, :ok, opts)
end
@impl true
def init(:ok) do
Process.flag(:trap_exit, true)
children = [
{Testcontainers.ReaperWorker, []},
]
Supervisor.init(children, strategy: :one_for_one)
end
end
defmodule Testcontainers.ReaperWorker do
use GenServer
require Logger
alias Testcontainers.Docker
alias Testcontainers.Container
@ryuk_image "testcontainers/ryuk:0.5.1"
@ryuk_port 8080
def start_link(_) do
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
end
def register(filter) do
if Process.whereis(__MODULE__) do
GenServer.cast(__MODULE__, {:register, filter})
else
Logger.warning("""
Reaper is not running! Ensure that Testcontainers.Reaper
is started in your test_helper.exs.
e.g.,
Testcontainers.Reaper.start_link()
""")
end
end
@impl true
def init(_) do
Process.flag(:trap_exit, true)
with {:ok, container} <- create_ryuk_container(),
{:ok, socket} <- create_ryuk_socket(container) do
Logger.info("Reaper initialized with containerId #{container.container_id}")
{:ok, %{socket: socket, container: container}}
else
error ->
{:stop, "Failed to start reaper: #{inspect(error)}"}
end
end
@impl true
def handle_cast({:register, filter}, %{socket: socket} = state) do
case register(socket, filter) do
:ok ->
{:noreply, state}
{:error, _reason} ->
{:stop, :error_reason, state}
end
end
defp register(socket, {filter_key, filter_value}) do
:gen_tcp.send(
socket,
"#{:uri_string.quote(filter_key)}=#{:uri_string.quote(filter_value)}" <> "\n"
)
case :gen_tcp.recv(socket, 0, 1_000) do
{:ok, "ACK\n"} ->
:ok
{:error, reason} ->
Logger.warning("Error receiving data: #{inspect(reason)}")
{:error, reason}
end
end
defp create_ryuk_container do
%Container{image: @ryuk_image}
|> Container.with_exposed_port(@ryuk_port)
|> Container.with_environment("RYUK_PORT", "#{@ryuk_port}")
|> Container.with_environment("RYUK_CONNECTION_TIMEOUT", "120s")
|> Container.with_bind_mount("/var/run/docker.sock", "/var/run/docker.sock", "rw")
|> Docker.Api.run(reap: false)
end
defp create_ryuk_socket(%Container{} = container) do
host_port = Container.mapped_port(container, @ryuk_port)
:gen_tcp.connect(~c"localhost", host_port, [
:binary,
active: false,
packet: :line
])
end
end