140 lines
4.2 KiB
Elixir
140 lines
4.2 KiB
Elixir
defmodule ServerWeb.HostChannelTest do
|
|
use ServerWeb.ChannelCase, async: false
|
|
|
|
alias Server.Hosts
|
|
alias ServerWeb.AgentSocket
|
|
|
|
setup do
|
|
{:ok, {host, token}} = Hosts.create_host("pve-01")
|
|
%{host: host, token: token}
|
|
end
|
|
|
|
describe "join" do
|
|
test "succeeds with valid token and marks host online", %{host: host, token: token} do
|
|
{:ok, socket} = connect(AgentSocket, %{})
|
|
|
|
assert {:ok, _reply, socket} =
|
|
subscribe_and_join(socket, "host:pve-01", %{
|
|
"token" => token,
|
|
"agent_version" => "0.1.0"
|
|
})
|
|
|
|
assert socket.assigns.host_id == host.id
|
|
|
|
reloaded = Server.Repo.reload!(host)
|
|
assert reloaded.status == "online"
|
|
assert reloaded.agent_version == "0.1.0"
|
|
assert reloaded.last_seen_at != nil
|
|
end
|
|
|
|
test "rejects invalid token" do
|
|
{:ok, socket} = connect(AgentSocket, %{})
|
|
|
|
assert {:error, %{reason: "invalid_token"}} =
|
|
subscribe_and_join(socket, "host:pve-01", %{
|
|
"token" => "garbage",
|
|
"agent_version" => "0.1.0"
|
|
})
|
|
end
|
|
|
|
test "rejects unknown host name" do
|
|
{:ok, socket} = connect(AgentSocket, %{})
|
|
|
|
assert {:error, %{reason: "unknown_host"}} =
|
|
subscribe_and_join(socket, "host:nope", %{
|
|
"token" => "x",
|
|
"agent_version" => "0.1.0"
|
|
})
|
|
end
|
|
end
|
|
|
|
describe "metric events persist to DB" do
|
|
setup %{token: token, host: host} do
|
|
{:ok, socket} = connect(AgentSocket, %{})
|
|
|
|
{:ok, _reply, joined} =
|
|
subscribe_and_join(socket, "host:pve-01", %{
|
|
"token" => token,
|
|
"agent_version" => "0.1.0"
|
|
})
|
|
|
|
%{socket: joined, host: host}
|
|
end
|
|
|
|
test "metric:fast is stored with interval=fast", %{socket: socket, host: host} do
|
|
ts = "2026-04-21T12:00:00.123456Z"
|
|
|
|
ref =
|
|
push(socket, "metric:fast", %{
|
|
"collected_at" => ts,
|
|
"data" => %{"cpu_percent" => 12.3, "load1" => 0.2}
|
|
})
|
|
|
|
assert_reply ref, :ok
|
|
|
|
sample = Server.Metrics.latest_sample(host.id, "fast")
|
|
assert sample != nil
|
|
assert sample.payload == %{"cpu_percent" => 12.3, "load1" => 0.2}
|
|
{:ok, expected, _} = DateTime.from_iso8601(ts)
|
|
assert DateTime.compare(sample.collected_at, expected) == :eq
|
|
end
|
|
|
|
test "metric:medium is stored with interval=medium", %{socket: socket, host: host} do
|
|
ref =
|
|
push(socket, "metric:medium", %{
|
|
"collected_at" => "2026-04-21T12:05:00Z",
|
|
"data" => %{"vms_detail" => []}
|
|
})
|
|
|
|
assert_reply ref, :ok
|
|
|
|
sample = Server.Metrics.latest_sample(host.id, "medium")
|
|
assert sample != nil
|
|
assert sample.payload == %{"vms_detail" => []}
|
|
end
|
|
|
|
test "metric:slow is stored with interval=slow", %{socket: socket, host: host} do
|
|
ref =
|
|
push(socket, "metric:slow", %{
|
|
"collected_at" => "2026-04-21T12:30:00Z",
|
|
"data" => %{"system_info" => %{"pveversion" => "8.3.0"}}
|
|
})
|
|
|
|
assert_reply ref, :ok
|
|
|
|
sample = Server.Metrics.latest_sample(host.id, "slow")
|
|
assert sample != nil
|
|
assert sample.payload == %{"system_info" => %{"pveversion" => "8.3.0"}}
|
|
end
|
|
|
|
test "replies :error when collected_at is missing", %{socket: socket} do
|
|
ref = push(socket, "metric:fast", %{"data" => %{}})
|
|
assert_reply ref, :error, %{reason: "missing_collected_at"}
|
|
end
|
|
|
|
test "replies :error when data is missing", %{socket: socket} do
|
|
ref = push(socket, "metric:fast", %{"collected_at" => "2026-04-21T12:00:00Z"})
|
|
assert_reply ref, :error, %{reason: "missing_data"}
|
|
end
|
|
end
|
|
|
|
describe "terminate" do
|
|
test "marks host offline when channel process exits", %{host: host, token: token} do
|
|
{:ok, socket} = connect(AgentSocket, %{})
|
|
|
|
{:ok, _, joined} =
|
|
subscribe_and_join(socket, "host:pve-01", %{
|
|
"token" => token,
|
|
"agent_version" => "0.1.0"
|
|
})
|
|
|
|
Process.unlink(joined.channel_pid)
|
|
ref = Process.monitor(joined.channel_pid)
|
|
close(joined)
|
|
assert_receive {:DOWN, ^ref, :process, _, _}, 1_000
|
|
|
|
reloaded = Server.Repo.reload!(host)
|
|
assert reloaded.status == "offline"
|
|
end
|
|
end
|
|
end
|