From d2e0400a8aeb99109375bb955e0a9f4cfb184aca Mon Sep 17 00:00:00 2001 From: Benjamin Brewer Date: Tue, 9 Jun 2020 14:44:21 -0400 Subject: [PATCH 1/5] add Divo.Suite.start, which allows for suite-wide docker setup --- lib/divo.ex | 53 +++++++++++++++++++++++---------------- lib/divo/suite.ex | 18 +++++++++++++ mix.exs | 2 +- test/integration_test.exs | 21 ++++++++++++++++ 4 files changed, 71 insertions(+), 23 deletions(-) create mode 100644 lib/divo/suite.ex 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..7af71b6 --- /dev/null +++ b/lib/divo/suite.ex @@ -0,0 +1,18 @@ +defmodule Divo.Suite do + @moduledoc false + + def start(opts \\ []) do + exit_hook = Keyword.get(opts, :exit_hook, &System.at_exit/1) + exit_arity = Keyword.get(opts, :exit_arity, 1) + + Divo.start(opts) + + exit_func = + case exit_arity do + 1 -> fn _ -> Divo.cleanup(opts) end + _ -> fn -> Divo.cleanup(opts) end + end + + exit_hook.(exit_func) + 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..8b65503 100644 --- a/test/integration_test.exs +++ b/test/integration_test.exs @@ -116,6 +116,27 @@ 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(exit_hook: &on_exit/1, exit_arity: 0) + + {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], exit_hook: &on_exit/1, exit_arity: 0) + + {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() From 96563617a7eabdffbf507e5493f06ef9a899584b Mon Sep 17 00:00:00 2001 From: "marqueeBen Brewer, Your Princi\"pal\" Artisan/marquee" Date: Tue, 9 Jun 2020 18:22:14 -0400 Subject: [PATCH 2/5] Update README.md --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 3aff337..ee187f9 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,23 @@ 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: +- `exit_hook` - the function to register the cleanup into. Defaults to `&System.at_exit/1` +- `exit_arity` - the arity function that the exit hook expects. Defaults to `1` as `&System.at_exit/1` expects this + ## Running Integration Tests Integration tests are executed by running: From d4f5aa32684cca2fa2697a92d30cdae64d739cb2 Mon Sep 17 00:00:00 2001 From: "marqueeBen Brewer, Your Princi\"pal\" Artisan/marquee" Date: Tue, 9 Jun 2020 18:33:39 -0400 Subject: [PATCH 3/5] Update README.md --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ee187f9..75271c2 100644 --- a/README.md +++ b/README.md @@ -172,8 +172,13 @@ This will make Divo stand up dockers that last the entire run of the test suite 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: -- `exit_hook` - the function to register the cleanup into. Defaults to `&System.at_exit/1` -- `exit_arity` - the arity function that the exit hook expects. Defaults to `1` as `&System.at_exit/1` expects this +- `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 From 59a013d87c1f2c39935b0e3a255d7a54984f10ce Mon Sep 17 00:00:00 2001 From: Benjamin Brewer Date: Tue, 9 Jun 2020 18:33:55 -0400 Subject: [PATCH 4/5] change cleanup hook to just be passed back https://github.com/SmartColumbusOS/scosopedia/issues/218 --- lib/divo/suite.ex | 16 ++++++++-------- test/integration_test.exs | 6 ++++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/divo/suite.ex b/lib/divo/suite.ex index 7af71b6..a6c275f 100644 --- a/lib/divo/suite.ex +++ b/lib/divo/suite.ex @@ -2,17 +2,17 @@ defmodule Divo.Suite do @moduledoc false def start(opts \\ []) do - exit_hook = Keyword.get(opts, :exit_hook, &System.at_exit/1) - exit_arity = Keyword.get(opts, :exit_arity, 1) + auto_cleanup? = Keyword.get(opts, :auto_cleanup?, true) Divo.start(opts) - exit_func = - case exit_arity do - 1 -> fn _ -> Divo.cleanup(opts) end - _ -> fn -> Divo.cleanup(opts) end - end + if auto_cleanup? do + System.at_exit(fn + _ -> Divo.cleanup(opts) + end) + end - exit_hook.(exit_func) + cleanup_hook = fn -> Divo.cleanup(opts) end + cleanup_hook end end diff --git a/test/integration_test.exs b/test/integration_test.exs index 8b65503..ee75e3b 100644 --- a/test/integration_test.exs +++ b/test/integration_test.exs @@ -120,7 +120,8 @@ defmodule IntegrationLogTest do use ExUnit.Case test "all parts of the stack are stood up by default" do - Divo.Suite.start(exit_hook: &on_exit/1, exit_arity: 0) + Divo.Suite.start(auto_cleanup?: false) + |> on_exit() {containers, _} = System.cmd("docker", ["ps", "-a"], stderr_to_stdout: true) @@ -128,7 +129,8 @@ defmodule IntegrationLogTest do end test "some parts of the stack are stood up by when supplied" do - Divo.Suite.start(services: [:alpine], exit_hook: &on_exit/1, exit_arity: 0) + Divo.Suite.start(services: [:alpine], auto_cleanup?: false) + |> on_exit() {containers, _} = System.cmd("docker", ["ps", "-a"], stderr_to_stdout: true) From 101567694e562f29ce3159966cd217eadc36a658 Mon Sep 17 00:00:00 2001 From: "marqueeBen Brewer, Your Princi\"pal\" Artisan/marquee" Date: Wed, 10 Jun 2020 09:15:35 -0400 Subject: [PATCH 5/5] Update lib/divo/suite.ex Johnson knows best Co-authored-by: Johnson Denen --- lib/divo/suite.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/divo/suite.ex b/lib/divo/suite.ex index a6c275f..6ad5a27 100644 --- a/lib/divo/suite.ex +++ b/lib/divo/suite.ex @@ -12,7 +12,6 @@ defmodule Divo.Suite do end) end - cleanup_hook = fn -> Divo.cleanup(opts) end - cleanup_hook + fn -> Divo.cleanup(opts) end end end