Some checks failed
Build and Push / Build and Push Docker Image (push) Failing after 2s
101 lines
2.9 KiB
Elixir
101 lines
2.9 KiB
Elixir
defmodule AprsmeWeb.MapLive.PacketBatcherTest do
|
|
use ExUnit.Case, async: true
|
|
|
|
alias AprsmeWeb.MapLive.PacketBatcher
|
|
|
|
setup do
|
|
# Trap exits so linked batcher doesn't crash the test process
|
|
Process.flag(:trap_exit, true)
|
|
:ok
|
|
end
|
|
|
|
describe "start_link/1" do
|
|
test "starts a batcher process" do
|
|
{:ok, pid} = PacketBatcher.start_link(self())
|
|
assert Process.alive?(pid)
|
|
GenServer.stop(pid)
|
|
end
|
|
end
|
|
|
|
describe "batching behavior" do
|
|
test "rejects stale and duplicate timestamped packets for a sender" do
|
|
{:ok, pid} = PacketBatcher.start_link(self())
|
|
newer_at = ~U[2026-01-02 00:00:00Z]
|
|
older_at = ~U[2026-01-01 00:00:00Z]
|
|
|
|
PacketBatcher.add_packet(pid, %{sender: "ORDER-1", received_at: newer_at})
|
|
PacketBatcher.add_packet(pid, %{sender: "ORDER-1", received_at: older_at})
|
|
PacketBatcher.add_packet(pid, %{sender: "ORDER-1", received_at: newer_at})
|
|
PacketBatcher.flush(pid)
|
|
|
|
assert_receive {:packet_batch, [%{received_at: ^newer_at}]}, 1_000
|
|
refute_receive {:packet_batch, _}, 100
|
|
|
|
GenServer.stop(pid)
|
|
end
|
|
|
|
test "delivers packets in batch after timeout" do
|
|
{:ok, pid} = PacketBatcher.start_link(self())
|
|
|
|
PacketBatcher.add_packet(pid, %{sender: "TEST-1"})
|
|
PacketBatcher.add_packet(pid, %{sender: "TEST-2"})
|
|
|
|
# Should receive batch after the 100ms timeout
|
|
assert_receive {:packet_batch, packets}, 1000
|
|
assert length(packets) == 2
|
|
assert Enum.at(packets, 0).sender == "TEST-1"
|
|
assert Enum.at(packets, 1).sender == "TEST-2"
|
|
|
|
GenServer.stop(pid)
|
|
end
|
|
|
|
test "delivers immediately when batch size reached" do
|
|
{:ok, pid} = PacketBatcher.start_link(self())
|
|
|
|
# Send 10 packets (batch size threshold)
|
|
for i <- 1..10 do
|
|
PacketBatcher.add_packet(pid, %{sender: "TEST-#{i}"})
|
|
end
|
|
|
|
# Should receive immediately (not waiting for timeout)
|
|
assert_receive {:packet_batch, packets}, 1000
|
|
assert length(packets) == 10
|
|
|
|
GenServer.stop(pid)
|
|
end
|
|
|
|
test "flush/1 delivers buffered packets immediately" do
|
|
{:ok, pid} = PacketBatcher.start_link(self())
|
|
|
|
PacketBatcher.add_packet(pid, %{sender: "TEST-1"})
|
|
PacketBatcher.flush(pid)
|
|
|
|
assert_receive {:packet_batch, [%{sender: "TEST-1"}]}, 1000
|
|
|
|
GenServer.stop(pid)
|
|
end
|
|
end
|
|
|
|
describe "crash recovery" do
|
|
test "batcher stops when parent dies" do
|
|
# Start a temporary parent process that traps exits
|
|
parent =
|
|
spawn(fn ->
|
|
Process.flag(:trap_exit, true)
|
|
|
|
receive do
|
|
:stop -> :ok
|
|
end
|
|
end)
|
|
|
|
{:ok, batcher_pid} = PacketBatcher.start_link(parent)
|
|
ref = Process.monitor(batcher_pid)
|
|
|
|
# Kill the parent
|
|
Process.exit(parent, :kill)
|
|
|
|
# Batcher should stop
|
|
assert_receive {:DOWN, ^ref, :process, ^batcher_pid, :normal}, 1000
|
|
end
|
|
end
|
|
end
|