defmodule Runbox.Runtime.Stage.Sandbox.TestRunner do
@moduledoc """
For new unit testing of scenarios it is recommended to use functions in
`Runbox.Runtime.Stage.Sandbox` directly. This module should only help to
convert old scenarios integration tests (using Solutions.TestRunner) to unit
tests. For examples of such conversion see tests in the scenarios master
branch.
"""
alias Runbox.Runtime.Stage.Sandbox
import ExUnit.Assertions
@doc """
Runs an unit test according to the `test_def` definition.
Function accepts the same `test_def` definition as `Solutions.TestRunner.run_test/1`
with few differences:
* Only `run_options.scenario_id`, `run_options.start_from`, `messages` and `expected_actions`
properties are used, other properties are ignored.
* Instead of output log format `expected_actions` are `Toolbox.Scenario.OutputAction`
structures, for example
```
%{
action: :add_asset,
params: %{attributes: %{}, id: "/diamonds/O"},
result: "nil",
serialization_vector: ["/diamonds/O"],
side_effects: false,
timestamp: 1
}
```
must be changed to:
```
%OutputAction{
type: :add_asset,
body: %Asset{attributes: %{}, id: "/diamonds/O"},
svector: ["/diamonds/O"],
timestamp: 1
}
```
To see differences take a look at `deduplication_diamond_test.exs` in scenarios and
the same test in solutions.
"""
def run_test(test_def) do
opts =
if test_def.run_options[:start_from] do
[start_from: test_def.run_options.start_from]
else
[]
end
{:ok, oas} = Sandbox.execute_run(test_def.messages, test_def.run_options.scenario_id, opts)
assert_output_actions!(oas, test_def[:expected_actions])
end
defp assert_output_actions!(got_actions, expected_actions) when is_function(expected_actions) do
expected_actions.(got_actions)
:ok
end
defp assert_output_actions!(got_actions, expected_actions) when is_list(expected_actions) do
missing = set_difference(expected_actions, got_actions)
unexpected = set_difference(got_actions, expected_actions)
assert {missing, unexpected} == {[], []}
:ok
end
defp set_difference(a, b), do: MapSet.to_list(MapSet.difference(MapSet.new(a), MapSet.new(b)))
end