Current section

Files

Jump to
fast_ci lib mix tasks fast_ci.test.ex
Raw

lib/mix/tasks/fast_ci.test.ex

defmodule Mix.Tasks.FastCi.Test do
require Logger
use Mix.Task
# iex --sname test -S mix app.test
alias FastCi.Versionless
@preferred_cli_env :test
def run(_args) do
Application.ensure_all_started(:ex_unit)
# The take calls fail unless this is called beforehand
Mix.Task.run("app.start")
__MODULE__.Traverser.load_modules("test")
# TODO: Find a way to hide the error message.
_time = Versionless.ensure_ex_unit_modules_loaded()
async =
ExUnit.Server.take_async_modules(5_000)
|> List.wrap()
|> Enum.map(fn async_module -> to_string(async_module) <> "#async" end)
|> tap(&Logger.info("Loaded async test modules: #{inspect(&1)}"))
sync =
ExUnit.Server.take_sync_modules()
|> List.wrap()
|> Enum.map(fn sync_module -> to_string(sync_module) <> "#sync" end)
|> tap(&Logger.info("Loaded sync test modules: #{inspect(&1)}"))
{:ok, pid} = FastCi.connect_to_test_orchestrator("ex_unit", async ++ sync)
Process.monitor(pid)
receive_loop(pid)
end
def receive_loop(server_pid) do
receive do
{:DOWN, _ref, :process, ^server_pid, {:shutdown, {:tests_done, false}}} ->
IO.write("All tests on the node have passed.\n")
System.halt(0)
{:DOWN, _ref, :process, ^server_pid, {:shutdown, {:tests_done, true}}} ->
IO.write(:stderr, "Some tests on the node have failed!\n")
System.halt(1)
{:DOWN, _ref, :process, ^server_pid, {:shutdown, {:node_timeout, _}}} ->
IO.write(:stderr, "Node wasn't active nor received any commands!\n")
System.halt(2)
{:DOWN, _ref, :process, ^server_pid, {:shutdown, :failed_connection}} ->
IO.write(:stderr, "Failed to connect to the orchestrator server!\n\nPlease contact customer support!\n")
System.halt(2)
{:DOWN, _ref, :process, ^server_pid, {:shutdown, :invalid_secret_key}} ->
IO.write(:stderr, "Failed to connect to he orchestrator server due to an invalid secret key!\n")
System.halt(2)
{:DOWN, _ref, :process, ^server_pid, {:shutdown, :invalid_run_key}} ->
IO.write(:stderr, "Failed to connect to the orchestrator server due to an invalid or disabled run key!\n")
System.halt(2)
{:DOWN, _ref, :process, ^server_pid, {:shutdown, {{:failed_join, join_state}, _}}} ->
IO.write(:stderr, "Failed to connect because of current test state: #{inspect(join_state)}")
System.halt(2)
{:DOWN, _ref, :process, ^server_pid, :connection_closed} ->
IO.write(:stderr, "Connection to the orchestrator server was closed!\n")
System.halt(3)
_ ->
receive_loop(server_pid)
end
end
# iex --sname node_test -S mix
# Node.spawn_link(:"test@posao", fn -> ExUnit.Server.add_sync_module(Utils.TimeUtilsTest) end)
# Node.spawn_link(:"test@posao", fn -> ExUnit.Runner.run(ExUnit.configuration(), ExUnit.Server.modules_loaded()) end)
defmodule Traverser do
def load_modules(path) do
start_time = System.system_time(:millisecond)
recursive_ls(path)
|> Enum.filter(&Regex.run(~r/\.(exs|ex)$/, &1))
|> tap(
&Logger.debug(
"Matched test and helper paths are: #{inspect(&1)} after #{System.system_time(:millisecond) - start_time}ms."
)
)
|> tap(&Enum.each(&1, fn file -> load_static(file) end))
|> tap(&Enum.each(&1, fn file -> load_dynamic(file) end))
end
defp load_static(file_path) do
if String.ends_with?(file_path, ".ex") do
file_path
|> tap(&Logger.debug("Loading static path: #{&1}"))
|> Code.require_file()
end
end
defp load_dynamic(file_path) do
if String.ends_with?(file_path, ".exs") do
file_path
|> tap(&Logger.debug("Loading dynamic path: #{&1}"))
|> Code.require_file()
end
end
defp recursive_ls(path) do
case File.ls(path) do
{:ok, entries} ->
entries
|> Enum.map(&Path.join(path, &1))
|> Enum.flat_map(&process_entry/1)
end
end
defp process_entry(entry) do
if File.dir?(entry) do
recursive_ls(entry)
else
[entry]
end
end
end
end