From 659ef70b9e4af7e504633a1a2aea44bf6eb6a0f7 Mon Sep 17 00:00:00 2001 From: Thomas Weustenfeld Date: Sat, 11 May 2024 08:54:02 -0400 Subject: [PATCH 1/2] added with_auth --- lib/container.ex | 16 ++++++++++++++++ lib/docker/api.ex | 6 ++++-- lib/testcontainers.ex | 2 +- test/container_test.exs | 17 +++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 test/container_test.exs diff --git a/lib/container.ex b/lib/container.ex index c89e7ca..3313a2a 100644 --- a/lib/container.ex +++ b/lib/container.ex @@ -11,6 +11,7 @@ defmodule Testcontainers.Container do :image, cmd: nil, environment: %{}, + auth: nil, exposed_ports: [], ip_address: nil, wait_strategies: [], @@ -130,6 +131,21 @@ defmodule Testcontainers.Container do %__MODULE__{config | auto_remove: auto_remove} end + @doc """ + Adds authentication token for registries that require a login. + """ + def with_auth(%__MODULE__{} = config, username, password) + when is_binary(username) and is_binary(password) do + registry_auth_token = + Jason.encode!(%{ + username: username, + password: password + }) + |> Base.encode64() + + %__MODULE__{config | auth: registry_auth_token} + end + @doc """ Gets the host port on the container for the given exposed port. """ diff --git a/lib/docker/api.ex b/lib/docker/api.ex index b2a3434..669795c 100644 --- a/lib/docker/api.ex +++ b/lib/docker/api.ex @@ -22,8 +22,10 @@ defmodule Testcontainers.Docker.Api do end end - def pull_image(image, conn) when is_binary(image) do - case Api.Image.image_create(conn, fromImage: image) do + def pull_image(image, conn, opts \\ []) when is_binary(image) do + auth = Keyword.get(opts, :auth, nil) + + case Api.Image.image_create(conn, fromImage: image, "X-Registry-Auth": auth) do {:ok, %Tesla.Env{status: 200}} -> {:ok, nil} diff --git a/lib/testcontainers.ex b/lib/testcontainers.ex index 9d90842..f7c3a98 100644 --- a/lib/testcontainers.ex +++ b/lib/testcontainers.ex @@ -211,7 +211,7 @@ defmodule Testcontainers do |> Container.with_label(container_lang_label(), container_lang_value()) |> Container.with_label(container_label(), "#{true}") - with {:ok, _} <- Api.pull_image(config.image, state.conn), + with {:ok, _} <- Api.pull_image(config.image, state.conn, auth: config.auth), {:ok, id} <- Api.create_container(config, state.conn), :ok <- Api.start_container(id, state.conn), {:ok, container} <- Api.get_container(id, state.conn), diff --git a/test/container_test.exs b/test/container_test.exs new file mode 100644 index 0000000..3fc5695 --- /dev/null +++ b/test/container_test.exs @@ -0,0 +1,17 @@ +defmodule Testcontainers.ContainerTest do + use ExUnit.Case, async: true + + alias Testcontainers.Container + + describe "with_auth/3" do + test "sets the authentication token for the container" do + container = Container.new("my-image") + assert container.auth == nil + + updated_container = Container.with_auth(container, "username", "password") + + assert updated_container.auth == + "eyJwYXNzd29yZCI6InBhc3N3b3JkIiwidXNlcm5hbWUiOiJ1c2VybmFtZSJ9" + end + end +end From e68bd40ce4b30a1e9a78236dfd5aa6db7e12d0c8 Mon Sep 17 00:00:00 2001 From: Thomas Weustenfeld Date: Sat, 11 May 2024 08:54:26 -0400 Subject: [PATCH 2/2] added container tests + fixed bug in with_fixed_port --- lib/container.ex | 25 +++++++++------ test/container_test.exs | 70 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 10 deletions(-) diff --git a/lib/container.ex b/lib/container.ex index 3313a2a..718bb93 100644 --- a/lib/container.ex +++ b/lib/container.ex @@ -61,6 +61,15 @@ defmodule Testcontainers.Container do %__MODULE__{config | exposed_ports: [port | filtered_ports]} end + @doc """ + Adds multiple _ports_ to be exposed on the _container_. + """ + def with_exposed_ports(%__MODULE__{} = config, ports) when is_list(ports) do + filtered_ports = config.exposed_ports |> Enum.reject(fn port -> port in ports end) + + %__MODULE__{config | exposed_ports: ports ++ filtered_ports} + end + @doc """ Adds a fixed _port_ to be exposed on the _container_. This approach to managing ports is not recommended by Testcontainers. @@ -68,7 +77,12 @@ defmodule Testcontainers.Container do """ def with_fixed_port(%__MODULE__{} = config, port, host_port \\ nil) when is_integer(port) and (is_nil(host_port) or is_integer(host_port)) do - filtered_ports = config.exposed_ports |> Enum.reject(fn p -> p == port end) + filtered_ports = + config.exposed_ports + |> Enum.reject(fn + {p, _} -> p == port + p -> p == port + end) %__MODULE__{ config @@ -78,15 +92,6 @@ defmodule Testcontainers.Container do } end - @doc """ - Adds multiple _ports_ to be exposed on the _container_. - """ - def with_exposed_ports(%__MODULE__{} = config, ports) when is_list(ports) do - filtered_ports = config.exposed_ports |> Enum.reject(fn port -> port in ports end) - - %__MODULE__{config | exposed_ports: ports ++ filtered_ports} - end - @doc """ Sets a file or the directory on the _host machine_ to be mounted into a _container_. """ diff --git a/test/container_test.exs b/test/container_test.exs index 3fc5695..b4c10dd 100644 --- a/test/container_test.exs +++ b/test/container_test.exs @@ -3,6 +3,76 @@ defmodule Testcontainers.ContainerTest do alias Testcontainers.Container + describe "with_exposed_port/2" do + test "adds an exposed port to the container" do + container = + Container.new("my-image") + |> Container.with_exposed_port(80) + + assert container.exposed_ports == [80] + end + + test "removes duplicate exposed ports" do + container = + Container.new("my-image") + |> Container.with_exposed_port(80) + |> Container.with_exposed_port(80) + + assert container.exposed_ports == [80] + end + end + + describe "with_exposed_ports/2" do + test "adds multiple exposed ports to the container" do + container = + Container.new("my-image") + |> Container.with_exposed_ports([80, 443]) + + assert container.exposed_ports == [80, 443] + end + + test "removes duplicate exposed ports" do + container = + Container.new("my-image") + |> Container.with_exposed_ports([80, 443]) + |> Container.with_exposed_ports([80]) + + assert container.exposed_ports == [80, 443] + end + end + + describe "with_fixed_port/3" do + test "adds a fixed exposed port to the container" do + container = + Container.new("my-image") + |> Container.with_fixed_port(80, 8080) + + assert container.exposed_ports == [{80, 8080}] + end + + test "removes and overwrites duplicate fixed ports" do + container = + Container.new("my-image") + |> Container.with_fixed_port(80) + |> Container.with_fixed_port(80, 8080) + |> Container.with_fixed_port(80, 8081) + + assert container.exposed_ports == [{80, 8081}] + end + end + + describe "mapped_port/2" do + test "returns the mapped host port for the given exposed port" do + container = Container.new("my-image") |> Container.with_fixed_port(80, 8080) + assert Container.mapped_port(container, 80) == 8080 + end + + test "returns nil if the exposed port is not found" do + container = Container.new("my-image") + assert Container.mapped_port(container, 80) == nil + end + end + describe "with_auth/3" do test "sets the authentication token for the container" do container = Container.new("my-image")