diff --git a/lib/container.ex b/lib/container.ex index 6c605c7..dd85ea6 100644 --- a/lib/container.ex +++ b/lib/container.ex @@ -30,6 +30,7 @@ defmodule Testcontainers.Container do network_mode: nil, network: nil, hostname: nil, + name: nil, reuse: false, force_reuse: false, pull_policy: nil @@ -284,6 +285,17 @@ defmodule Testcontainers.Container do %__MODULE__{config | hostname: hostname} end + @doc """ + Sets a custom name for the container (equivalent to `docker run --name`). + + Must match `/?[a-zA-Z0-9][a-zA-Z0-9_.-]+`. This is useful when other + containers need to reference this container by name on a shared Docker + network. + """ + def with_name(%__MODULE__{} = config, name) when is_binary(name) do + %__MODULE__{config | name: name} + end + def with_copy_to(%__MODULE__{} = config, target, source) when is_binary(target) and is_binary(source) do %__MODULE__{ diff --git a/lib/docker/api.ex b/lib/docker/api.ex index 1b1ee63..644f1a4 100644 --- a/lib/docker/api.ex +++ b/lib/docker/api.ex @@ -88,7 +88,9 @@ defmodule Testcontainers.Docker.Api do end def create_container(%Container{} = container, conn) do - case Api.Container.container_create(conn, container_create_request(container)) do + opts = if container.name, do: [name: container.name], else: [] + + case Api.Container.container_create(conn, container_create_request(container), opts) do {:error, %Tesla.Env{status: other}} -> {:error, {:http_error, other}} diff --git a/test/container_test.exs b/test/container_test.exs index 80bc16c..0d7c73b 100644 --- a/test/container_test.exs +++ b/test/container_test.exs @@ -213,6 +213,30 @@ defmodule Testcontainers.ContainerTest do end end + describe "with_name/2" do + test "defaults to nil" do + container = Container.new("my-image") + assert container.name == nil + end + + test "sets the name on the container" do + container = + Container.new("my-image") + |> Container.with_name("my-container") + + assert container.name == "my-container" + end + + test "overwrites a previously set name" do + container = + Container.new("my-image") + |> Container.with_name("first") + |> Container.with_name("second") + + assert container.name == "second" + end + end + describe "with_privileged/2" do test "sets privileged to true" do container = Container.new("my-image") diff --git a/test/testcontainers_test.exs b/test/testcontainers_test.exs index c140c99..f16642e 100644 --- a/test/testcontainers_test.exs +++ b/test/testcontainers_test.exs @@ -41,6 +41,26 @@ defmodule TestcontainersTest do :ok = GenServer.stop(pid) end + test "assigns custom name to container via Container.with_name/2" do + name = "testcontainers-name-#{:rand.uniform(1_000_000)}" + + config = + Container.new("nginx:alpine") + |> Container.with_name(name) + + {:ok, pid} = Testcontainers.start_link(name: :name_test) + {:ok, container} = Testcontainers.start_container(config, :name_test) + + conn = Connection.get_connection() |> Tuple.to_list() |> Kernel.hd() + {:ok, %DockerEngineAPI.Model.ContainerInspectResponse{Name: assigned_name}} = + DockerEngineAPI.Api.Container.container_inspect(conn, container.container_id) + + # Docker returns the name prefixed with a leading "/" + assert assigned_name == "/" <> name + + :ok = GenServer.stop(pid) + end + test "initializes successfully when ryuk is disabled" do # Set environment variable to disable Ryuk System.put_env("TESTCONTAINERS_RYUK_DISABLED", "true")