diff --git a/README.md b/README.md index 3aff337..75271c2 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,28 @@ defmodule MyAppTest do end ``` +## Use Divo for the entire test suite +In your integration or test suite's `test_helper.exs` file add `Divo.Suite.start()` before `ExUnit.start()` +Example: +```elixir +Divo.Suite.start() +... +ExUnit.start() +``` + +This will make Divo stand up dockers that last the entire run of the test suite (or just a few modules or tests if you specified them in your `mix test.integration` command). It will wire itself up to tear down the dockers if in cases where the tests fail to compile. + +Ideally, you will want to NOT have `use Divo` in your tests. However, if you leave `use Divo` in for all of the tests, and still add the start to your `test_helper.exs` the tests will still run as expected, with an additional docker start and stop wrapped around the whole run. + +The `Divo.Suite.start` function takes all of the options that `use Divo` does plus a few extras for controlling where the final docker cleanup occurs: +- `auto_cleanup?` - whether or not to cleanup dockers on program exit. Defaults to `true` + +Whether or not you choose to let it cleanup after itself, `Divo.Suite.start` will return a zero-arity cleanup hook that you can call when you want to explicitly cleanup the dockers. +```elixir +Divo.Suite.start() +|> on_exit() +``` + ## Running Integration Tests Integration tests are executed by running: diff --git a/lib/divo.ex b/lib/divo.ex index 2728981..0a82e6d 100644 --- a/lib/divo.ex +++ b/lib/divo.ex @@ -13,40 +13,49 @@ defmodule Divo do your tests. """ defmacro __using__(opts \\ []) do - auto_start = Keyword.get(opts, :auto_start, true) - post_docker_run = Keyword.get(opts, :post_docker_run, []) - quote do + import Divo import Divo.Compose setup_all do - Divo.Compose.run(unquote(opts)) + start(unquote(opts)) + + on_exit(fn -> + cleanup(unquote(opts)) + end) + end + end + end - unquote(post_docker_run) - |> Enum.each(& &1.()) + def start(opts \\ []) do + auto_start = Keyword.get(opts, :auto_start, true) + post_docker_run = Keyword.get(opts, :post_docker_run, []) - app = Mix.Project.config() |> Keyword.get(:app) - if unquote(auto_start), do: Application.ensure_all_started(app) + Divo.Compose.run(opts) - on_exit(fn -> - if unquote(auto_start) do - dependent_apps = - Application.spec(app, :applications) -- - [:kernel, :stdlib, :elixir, :ex_unit, :logger, :divo, :placebo] + Enum.each(post_docker_run, & &1.()) - Logger.remove_backend(:console) + app = Mix.Project.config() |> Keyword.get(:app) + if auto_start, do: Application.ensure_all_started(app) + end - [app | dependent_apps] - |> Enum.each(&Application.stop/1) + def cleanup(opts \\ []) do + auto_start = Keyword.get(opts, :auto_start, true) + app = Mix.Project.config() |> Keyword.get(:app) - Logger.add_backend(:console) - end + if auto_start do + dependent_apps = + Application.spec(app, :applications) -- + [:kernel, :stdlib, :elixir, :ex_unit, :logger, :divo, :placebo] - Divo.Compose.kill() - end) + Logger.remove_backend(:console) - :ok - end + [app | dependent_apps] + |> Enum.each(&Application.stop/1) + + Logger.add_backend(:console) end + + Divo.Compose.kill() end end diff --git a/lib/divo/suite.ex b/lib/divo/suite.ex new file mode 100644 index 0000000..6ad5a27 --- /dev/null +++ b/lib/divo/suite.ex @@ -0,0 +1,17 @@ +defmodule Divo.Suite do + @moduledoc false + + def start(opts \\ []) do + auto_cleanup? = Keyword.get(opts, :auto_cleanup?, true) + + Divo.start(opts) + + if auto_cleanup? do + System.at_exit(fn + _ -> Divo.cleanup(opts) + end) + end + + fn -> Divo.cleanup(opts) end + end +end diff --git a/mix.exs b/mix.exs index 0c29952..abdf318 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Divo.MixProject do def project do [ app: :divo, - version: "1.2.0", + version: "1.3.0", elixir: "~> 1.8", start_permanent: Mix.env() == :prod, deps: deps(), diff --git a/test/integration_test.exs b/test/integration_test.exs index b1183a7..ee75e3b 100644 --- a/test/integration_test.exs +++ b/test/integration_test.exs @@ -116,6 +116,29 @@ defmodule IntegrationLogTest do end end + defmodule IntegrationSuiteTest do + use ExUnit.Case + + test "all parts of the stack are stood up by default" do + Divo.Suite.start(auto_cleanup?: false) + |> on_exit() + + {containers, _} = System.cmd("docker", ["ps", "-a"], stderr_to_stdout: true) + + assert String.contains?(containers, "busybox_1") + end + + test "some parts of the stack are stood up by when supplied" do + Divo.Suite.start(services: [:alpine], auto_cleanup?: false) + |> on_exit() + + {containers, _} = System.cmd("docker", ["ps", "-a"], stderr_to_stdout: true) + + assert String.contains?(containers, "busybox_1") == false + assert String.contains?(containers, "alpine_1") == true + end + end + defp check_logs_for(log, word) do log |> String.split()