defmodule Mix.Tasks.K6 do
@moduledoc """
Runs k6 commands
The command runs using the binary installed locally in the `_build` folder of the project.
If k6 is not installed for the local project, it will automatically install it before running the command.
k6 is executed in the folder where k6 tests reside, which defaults to `priv/k6`.
## Examples
$ mix k6 run my_test.js
$ mix k6 run --vus 10 --duration 30s my_test.js
"""
use Mix.Task
@shortdoc "Runs k6"
def run(args) when is_list(args) do
unless correct_version_installed?(), do: Mix.Task.run("k6.install")
test_dir = tests_directory()
unless File.exists?(test_dir), do: File.mkdir_p(test_dir)
wrapper_args = [binary_path() | args]
options = [
:nouse_stdio,
:exit_status,
args: wrapper_args,
cd: String.to_charlist(test_dir),
env: k6_env()
]
port = Port.open({:spawn_executable, wrapper_path()}, options)
receive do
{^port, {:exit_status, exit_status}} -> exit({:shutdown, exit_status})
end
end
defp k6_env do
stringify = fn s -> String.to_charlist(to_string(s)) end
:k6
|> Application.get_env(:env, [])
|> Enum.into([], fn {k, v} -> {stringify.(k), stringify.(v)} end)
end
defp binary_path, do: Path.join(Path.dirname(Mix.Project.build_path()), "k6")
defp wrapper_path, do: Path.join(Application.app_dir(:k6), "priv/wrapper.sh")
defp tests_directory, do: Application.get_env(:k6, :workdir, "priv/k6")
defp correct_version_installed? do
path = binary_path()
if File.exists?(path) do
expected_version = Application.get_env(:k6, :version, "v0.39.0")
installed_version() == expected_version
else
false
end
end
defp installed_version do
{res, 0 = _exit_code} = System.cmd(binary_path(), ["version"])
["k6", version | _] = String.split(res, " ", trim: true)
version
end
end