diff --git a/lib/ceph_container.ex b/lib/ceph_container.ex new file mode 100644 index 0000000..99716f6 --- /dev/null +++ b/lib/ceph_container.ex @@ -0,0 +1,3 @@ +defmodule TestcontainersElixir.CephContainer do + +end diff --git a/lib/containers.ex b/lib/containers.ex new file mode 100644 index 0000000..9759c1d --- /dev/null +++ b/lib/containers.ex @@ -0,0 +1,59 @@ +defmodule TestcontainersElixir.Containers do + alias DockerEngineAPI.Api + alias DockerEngineAPI.Model + alias DockerEngineAPI.Connection + alias TestcontainersElixir.Reaper + alias TestcontainersElixir.Container + + def container(options \\ [], on_exit) do + docker_url = "http+unix://%2Fvar%2Frun%2Fdocker.sock/v1.43" + conn = Connection.new(base_url: docker_url) + image = Keyword.get(options, :image, nil) + port = Keyword.get(options, :port, nil) + + with {:ok, _} <- Api.Image.image_create(conn, fromImage: image), + {:ok, container} <- create_simple_container(conn, image, port), + container_id = container."Id", + {:ok, _} <- Api.Container.container_start(conn, container_id), + :ok = + on_exit.(:stop_container, fn -> + with :ok <- reap_container(conn, container_id) do + stop_container(conn, container_id) + end + end) do + {:ok, get_container(conn, container_id)} + end + end + + defp stop_container(conn, container_id) when is_binary(container_id) do + with {:ok, _} <- Api.Container.container_kill(conn, container_id), + {:ok, _} <- Api.Container.container_delete(conn, container_id) do + :ok + end + end + + defp create_simple_container(conn, image, port) when is_binary(image) and is_number(port) do + Api.Container.container_create(conn, %Model.ContainerCreateRequest{ + Image: image, + ExposedPorts: %{"#{port}" => %{}}, + HostConfig: %{ + PortBindings: %{"#{port}/tcp" => [%{"HostIp" => "0.0.0.0", "HostPort" => ""}]} + } + }) + end + + defp get_container(conn, container_id) when is_binary(container_id) do + with {:ok, response} <- Api.Container.container_inspect(conn, container_id) do + Container.of(response) + end + end + + defp reap_container(conn, container_id) when is_binary(container_id) do + case conn |> Reaper.start_link() do + {:error, {:already_started, _}} -> :ok + {:ok, _} -> :ok + end + + Reaper.register({"id", container_id}) + end +end diff --git a/lib/ex_unit.ex b/lib/ex_unit.ex index 9df26dc..037c2ba 100644 --- a/lib/ex_unit.ex +++ b/lib/ex_unit.ex @@ -1,59 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 defmodule TestcontainersElixir.ExUnit do - alias TestcontainersElixir.Reaper - alias DockerEngineAPI.Connection - alias DockerEngineAPI.Api - alias DockerEngineAPI.Model + alias TestcontainersElixir.Containers - def container(options \\ [], on_exit \\ &ExUnit.Callbacks.on_exit/2) do - docker_url = "http+unix://%2Fvar%2Frun%2Fdocker.sock/v1.43" - conn = Connection.new(base_url: docker_url) - image = Keyword.get(options, :image, nil) - port = Keyword.get(options, :port, nil) - - with {:ok, _} <- Api.Image.image_create(conn, fromImage: image), - {:ok, container} <- create_simple_container(conn, image, port), - container_id = container."Id", - {:ok, _} <- Api.Container.container_start(conn, container_id), - :ok = - on_exit.(:stop_container, fn -> - with :ok <- reap_container(conn, container_id) do - stop_container(conn, container_id) - end - end) do - {:ok, get_container(conn, container_id)} - end - end - - defp stop_container(conn, container_id) when is_binary(container_id) do - with {:ok, _} <- Api.Container.container_kill(conn, container_id), - {:ok, _} <- Api.Container.container_delete(conn, container_id) do - :ok - end - end - - defp create_simple_container(conn, image, port) when is_binary(image) and is_number(port) do - Api.Container.container_create(conn, %Model.ContainerCreateRequest{ - Image: image, - ExposedPorts: %{"#{port}" => %{}}, - HostConfig: %{ - PortBindings: %{"#{port}/tcp" => [%{"HostIp" => "0.0.0.0", "HostPort" => ""}]} - } - }) - end - - defp get_container(conn, container_id) when is_binary(container_id) do - with {:ok, response} <- Api.Container.container_inspect(conn, container_id) do - TestcontainersElixir.Container.of(response) - end - end - - defp reap_container(conn, container_id) when is_binary(container_id) do - case conn |> Reaper.start_link() do - {:error, {:already_started, _}} -> :ok - {:ok, _} -> :ok - end - - Reaper.register({"id", container_id}) + def container(options \\ []) do + Containers.container(options, &ExUnit.Callbacks.on_exit/2) end end diff --git a/test/nginx_test.exs b/test/nginx_test.exs index 0bf89b6..04addd4 100644 --- a/test/nginx_test.exs +++ b/test/nginx_test.exs @@ -3,7 +3,7 @@ defmodule SimpleTest do import TestcontainersElixir.ExUnit - alias TestcontainersElixir.LogChecker + alias TestcontainersElixir.HttpChecker alias TestcontainersElixir.Container test "creates and uses container" do @@ -11,14 +11,16 @@ defmodule SimpleTest do port = Container.mapped_port(container, 80) - # this is just work in progress, the log ready check below needs it - # but we want to move this logic inside the container function above - # and make a better system for passing in waiting strategies - docker_url = "http+unix://%2Fvar%2Frun%2Fdocker.sock/v1.43" - conn = DockerEngineAPI.Connection.new(base_url: docker_url) + # # this is just work in progress, the log ready check below needs it + # # but we want to move this logic inside the container function above + # # and make a better system for passing in waiting strategies + # docker_url = "http+unix://%2Fvar%2Frun%2Fdocker.sock/v1.43" + # conn = DockerEngineAPI.Connection.new(base_url: docker_url) - {:ok, :log_is_ready} = - LogChecker.wait_for_log(conn, container.container_id, ~r/.*nginx\/.*/, 10000) + # {:ok, :log_is_ready} = + # LogChecker.wait_for_log(conn, container.container_id, ~r/.*nginx\/.*/, 10000) + + {:ok, :http_is_ready} = HttpChecker.wait_for_http("127.0.0.1", port, "/", 5000) {:ok, 200, _headers, body_ref} = :hackney.request(:get, "http://127.0.0.1:#{port}") {:ok, body} = :hackney.body(body_ref)