Packages
testcontainers
1.14.1
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/mix/tasks/testcontainers/run.ex
defmodule Mix.Tasks.Testcontainers.Run do
use Mix.Task
alias Testcontainers.PostgresContainer
alias Testcontainers.MySqlContainer
@shortdoc "Runs a Mix sub-task (test, phx.server, etc) with a database container"
@moduledoc """
Usage:
mix testcontainers.run [sub_task] [--database DB] [--db-volume VOLUME] [sub_task_args...]
Examples:
mix testcontainers.run test --database postgres
mix testcontainers.run phx.server --database mysql
mix testcontainers.run test --database postgres --db-volume my_postgres_data
mix testcontainers.run phx.server --db-volume my_postgres_data
mix testcontainers.run some.custom.server
"""
def run(args) do
Enum.each([:tesla, :hackney, :fs, :logger], fn app ->
{:ok, _} = Application.ensure_all_started(app)
end)
{:ok, _} = Testcontainers.start()
{opts, rest_args, _} =
OptionParser.parse(args,
switches: [
database: :string,
db_volume: :string,
host_port: :integer
]
)
database = opts[:database] || "postgres"
db_volume = opts[:db_volume]
host_port = opts[:host_port]
# Determine sub_task and its args
{sub_task, sub_task_args} =
case rest_args do
[task | tail] -> {task, tail}
[] -> {"test", []}
end
IO.puts("Starting database container: #{database}")
IO.puts("Using database volume: #{db_volume || "none"}")
{_container, env} = setup_container(database, db_volume, host_port)
run_sub_task_and_exit(sub_task, sub_task_args, env)
end
@spec run_sub_task_and_exit(String.t(), list(String.t()), list({String.t(), String.t()})) ::
no_return()
defp run_sub_task_and_exit(sub_task, sub_task_args, env) do
IO.puts("Starting mix task: #{sub_task} #{Enum.join(sub_task_args, " ")}")
Enum.each(env, fn {k, v} -> System.put_env(k, v) end)
:ok = Mix.Task.run(sub_task, sub_task_args)
IO.puts("Task finished: #{sub_task} #{Enum.join(sub_task_args, " ")}")
end
defp setup_container(database, db_volume, host_port) do
case database do
"postgres" ->
container_def =
PostgresContainer.new()
|> PostgresContainer.with_user("test")
|> PostgresContainer.with_password("test")
|> PostgresContainer.with_reuse(true)
|> maybe_with_host_port(host_port, PostgresContainer.default_port(), PostgresContainer)
|> maybe_with_persistent_volume(db_volume, PostgresContainer)
{:ok, container} = Testcontainers.start_container(container_def)
port = PostgresContainer.port(container)
{container, create_env(port)}
"mysql" ->
container_def =
MySqlContainer.new()
|> MySqlContainer.with_user("test")
|> MySqlContainer.with_password("test")
|> MySqlContainer.with_reuse(true)
|> maybe_with_host_port(host_port, MySqlContainer.default_port(), MySqlContainer)
|> maybe_with_persistent_volume(db_volume, MySqlContainer)
{:ok, container} = Testcontainers.start_container(container_def)
port = MySqlContainer.port(container)
{container, create_env(port)}
_ ->
raise("Unsupported database: #{database}")
end
end
defp maybe_with_host_port(config, nil, _exposed_port, _module), do: config
defp maybe_with_host_port(config, host_port, exposed_port, module) do
module.with_port(config, {exposed_port, host_port})
end
defp maybe_with_persistent_volume(config, nil, _module), do: config
defp maybe_with_persistent_volume(config, db_volume, module) do
module.with_persistent_volume(config, db_volume)
end
defp create_env(port) do
[
{"DATABASE_URL", "ecto://test:test@#{Testcontainers.get_host()}:#{port}/test"},
# for backward compability, will be removed in future releases
{"DB_USER", "test"},
{"DB_PASSWORD", "test"},
{"DB_HOST", Testcontainers.get_host()},
{"DB_PORT", Integer.to_string(port)}
]
end
end